Removed the autoStartDate and replaced it with the current startDate
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { Session } from "@/hooks/useSessions";
|
import { Session } from "@/hooks/useSessions";
|
||||||
import { Assignment } from "@/interfaces/results";
|
import { Assignment } from "@/interfaces/results";
|
||||||
import { User } from "@/interfaces/user";
|
import { User } from "@/interfaces/user";
|
||||||
|
import { activeAssignmentFilter, futureAssignmentFilter } from "@/utils/assignments";
|
||||||
import { sortByModuleName } from "@/utils/moduleUtils";
|
import { sortByModuleName } from "@/utils/moduleUtils";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
@@ -44,7 +45,16 @@ export default function AssignmentCard({ user, assignment, session, startAssignm
|
|||||||
<ModuleBadge className="scale-110 w-full" key={module} module={module} />
|
<ModuleBadge className="scale-110 w-full" key={module} module={module} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{!assignment.results.map((r) => r.user).includes(user.id) && (
|
{futureAssignmentFilter(assignment) && (
|
||||||
|
<Button
|
||||||
|
color="rose"
|
||||||
|
className="-md:hidden h-full w-full max-w-[50%] !rounded-xl"
|
||||||
|
disabled
|
||||||
|
variant="outline">
|
||||||
|
Not yet started
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{activeAssignmentFilter(assignment) && !assignment.results.map((r) => r.user).includes(user.id) && (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className="tooltip flex h-full w-full items-center justify-end pl-8 md:hidden"
|
className="tooltip flex h-full w-full items-center justify-end pl-8 md:hidden"
|
||||||
@@ -88,6 +98,7 @@ export default function AssignmentCard({ user, assignment, session, startAssignm
|
|||||||
<Button
|
<Button
|
||||||
color="green"
|
color="green"
|
||||||
className="-md:hidden h-full w-full max-w-[50%] !rounded-xl"
|
className="-md:hidden h-full w-full max-w-[50%] !rounded-xl"
|
||||||
|
disabled
|
||||||
variant="outline">
|
variant="outline">
|
||||||
Submitted
|
Submitted
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
import Input from "@/components/Low/Input";
|
import Input from "@/components/Low/Input";
|
||||||
import Modal from "@/components/Modal";
|
import Modal from "@/components/Modal";
|
||||||
import {Module} from "@/interfaces";
|
import { Module } from "@/interfaces";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import {useEffect, useMemo, useState} from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import {BsBook, BsCheckCircle, BsClipboard, BsHeadphones, BsMegaphone, BsPen, BsXCircle} from "react-icons/bs";
|
import { BsBook, BsCheckCircle, BsClipboard, BsHeadphones, BsMegaphone, BsPen, BsXCircle } from "react-icons/bs";
|
||||||
import {generate} from "random-words";
|
import { generate } from "random-words";
|
||||||
import {capitalize} from "lodash";
|
import { capitalize } from "lodash";
|
||||||
import useUsers from "@/hooks/useUsers";
|
import useUsers from "@/hooks/useUsers";
|
||||||
import {Group, User} from "@/interfaces/user";
|
import { Group, User } from "@/interfaces/user";
|
||||||
import ProgressBar from "@/components/Low/ProgressBar";
|
import ProgressBar from "@/components/Low/ProgressBar";
|
||||||
import {calculateAverageLevel} from "@/utils/score";
|
import { calculateAverageLevel } from "@/utils/score";
|
||||||
import Button from "@/components/Low/Button";
|
import Button from "@/components/Low/Button";
|
||||||
import ReactDatePicker from "react-datepicker";
|
import ReactDatePicker from "react-datepicker";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {getExam} from "@/utils/exams";
|
import { getExam } from "@/utils/exams";
|
||||||
import {toast} from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import {Assignment} from "@/interfaces/results";
|
import { Assignment } from "@/interfaces/results";
|
||||||
import Checkbox from "@/components/Low/Checkbox";
|
import Checkbox from "@/components/Low/Checkbox";
|
||||||
import {InstructorGender, Variant} from "@/interfaces/exam";
|
import { InstructorGender, Variant } from "@/interfaces/exam";
|
||||||
import Select from "@/components/Low/Select";
|
import Select from "@/components/Low/Select";
|
||||||
import useExams from "@/hooks/useExams";
|
import useExams from "@/hooks/useExams";
|
||||||
import {useListSearch} from "@/hooks/useListSearch";
|
import { useListSearch } from "@/hooks/useListSearch";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isCreating: boolean;
|
isCreating: boolean;
|
||||||
@@ -34,7 +34,7 @@ interface Props {
|
|||||||
|
|
||||||
const SIZE = 12;
|
const SIZE = 12;
|
||||||
|
|
||||||
export default function AssignmentCreator({isCreating, assignment, user, groups, users, cancelCreation}: Props) {
|
export default function AssignmentCreator({ isCreating, assignment, user, groups, users, cancelCreation }: Props) {
|
||||||
const [studentsPage, setStudentsPage] = useState(0);
|
const [studentsPage, setStudentsPage] = useState(0);
|
||||||
const [teachersPage, setTeachersPage] = useState(0);
|
const [teachersPage, setTeachersPage] = useState(0);
|
||||||
|
|
||||||
@@ -43,14 +43,14 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
|||||||
const [teachers, setTeachers] = useState<string[]>(!!assignment ? assignment.teachers || [] : [...(user.type === "teacher" ? [user.id] : [])]);
|
const [teachers, setTeachers] = useState<string[]>(!!assignment ? assignment.teachers || [] : [...(user.type === "teacher" ? [user.id] : [])]);
|
||||||
const [name, setName] = useState(
|
const [name, setName] = useState(
|
||||||
assignment?.name ||
|
assignment?.name ||
|
||||||
generate({
|
generate({
|
||||||
minLength: 6,
|
minLength: 6,
|
||||||
maxLength: 8,
|
maxLength: 8,
|
||||||
min: 2,
|
min: 2,
|
||||||
max: 3,
|
max: 3,
|
||||||
join: " ",
|
join: " ",
|
||||||
formatter: capitalize,
|
formatter: capitalize,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [startDate, setStartDate] = useState<Date | null>(assignment ? moment(assignment.startDate).toDate() : moment().add(1, "hour").toDate());
|
const [startDate, setStartDate] = useState<Date | null>(assignment ? moment(assignment.startDate).toDate() : moment().add(1, "hour").toDate());
|
||||||
@@ -65,18 +65,17 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
|||||||
const [released, setReleased] = useState<boolean>(assignment?.released || false);
|
const [released, setReleased] = useState<boolean>(assignment?.released || false);
|
||||||
|
|
||||||
const [autoStart, setAutostart] = useState<boolean>(assignment?.autoStart || false);
|
const [autoStart, setAutostart] = useState<boolean>(assignment?.autoStart || false);
|
||||||
const [autoStartDate, setAutoStartDate] = useState<Date | null>(assignment ? moment(assignment.autoStartDate).toDate() : new Date());
|
|
||||||
|
|
||||||
const [useRandomExams, setUseRandomExams] = useState(true);
|
const [useRandomExams, setUseRandomExams] = useState(true);
|
||||||
const [examIDs, setExamIDs] = useState<{id: string; module: Module}[]>([]);
|
const [examIDs, setExamIDs] = useState<{ id: string; module: Module }[]>([]);
|
||||||
|
|
||||||
const {exams} = useExams();
|
const { exams } = useExams();
|
||||||
|
|
||||||
const userStudents = useMemo(() => users.filter((x) => x.type === "student"), [users]);
|
const userStudents = useMemo(() => users.filter((x) => x.type === "student"), [users]);
|
||||||
const userTeachers = useMemo(() => users.filter((x) => x.type === "teacher"), [users]);
|
const userTeachers = useMemo(() => users.filter((x) => x.type === "teacher"), [users]);
|
||||||
|
|
||||||
const {rows: filteredStudentsRows, renderSearch: renderStudentSearch, text: studentText} = useListSearch([["name"], ["email"]], userStudents);
|
const { rows: filteredStudentsRows, renderSearch: renderStudentSearch, text: studentText } = useListSearch([["name"], ["email"]], userStudents);
|
||||||
const {rows: filteredTeachersRows, renderSearch: renderTeacherSearch, text: teacherText} = useListSearch([["name"], ["email"]], userTeachers);
|
const { rows: filteredTeachersRows, renderSearch: renderTeacherSearch, text: teacherText } = useListSearch([["name"], ["email"]], userTeachers);
|
||||||
|
|
||||||
useEffect(() => setStudentsPage(0), [studentText]);
|
useEffect(() => setStudentsPage(0), [studentText]);
|
||||||
const studentRows = useMemo(
|
const studentRows = useMemo(
|
||||||
@@ -131,7 +130,6 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
|||||||
instructorGender,
|
instructorGender,
|
||||||
released,
|
released,
|
||||||
autoStart,
|
autoStart,
|
||||||
autoStartDate,
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.success(`The assignment "${name}" has been ${assignment ? "updated" : "created"} successfully!`);
|
toast.success(`The assignment "${name}" has been ${assignment ? "updated" : "created"} successfully!`);
|
||||||
@@ -306,24 +304,6 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
|||||||
onChange={(date) => setEndDate(date)}
|
onChange={(date) => setEndDate(date)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{autoStart && (
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<label className="font-normal text-base text-mti-gray-dim">Automatic Start Date *</label>
|
|
||||||
<ReactDatePicker
|
|
||||||
className={clsx(
|
|
||||||
"p-6 w-full min-h-[70px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer",
|
|
||||||
"hover:border-mti-purple tooltip z-10",
|
|
||||||
"transition duration-300 ease-in-out",
|
|
||||||
)}
|
|
||||||
popperClassName="!z-20"
|
|
||||||
filterTime={(date) => moment(date).isSameOrAfter(new Date())}
|
|
||||||
dateFormat="dd/MM/yyyy HH:mm"
|
|
||||||
selected={autoStartDate}
|
|
||||||
showTimeSelect
|
|
||||||
onChange={(date) => setAutoStartDate(date)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedModules.includes("speaking") && (
|
{selectedModules.includes("speaking") && (
|
||||||
@@ -337,9 +317,9 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
|||||||
onChange={(value) => (value ? setInstructorGender(value.value as InstructorGender) : null)}
|
onChange={(value) => (value ? setInstructorGender(value.value as InstructorGender) : null)}
|
||||||
disabled={!selectedModules.includes("speaking") || !!assignment}
|
disabled={!selectedModules.includes("speaking") || !!assignment}
|
||||||
options={[
|
options={[
|
||||||
{value: "male", label: "Male"},
|
{ value: "male", label: "Male" },
|
||||||
{value: "female", label: "Female"},
|
{ value: "female", label: "Female" },
|
||||||
{value: "varied", label: "Varied"},
|
{ value: "varied", label: "Varied" },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -362,12 +342,12 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
|||||||
}}
|
}}
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
value
|
value
|
||||||
? setExamIDs((prev) => [...prev.filter((x) => x.module !== module), {id: value.value!, module}])
|
? setExamIDs((prev) => [...prev.filter((x) => x.module !== module), { id: value.value!, module }])
|
||||||
: setExamIDs((prev) => prev.filter((x) => x.module !== module))
|
: setExamIDs((prev) => prev.filter((x) => x.module !== module))
|
||||||
}
|
}
|
||||||
options={exams
|
options={exams
|
||||||
.filter((x) => !x.isDiagnostic && x.module === module)
|
.filter((x) => !x.isDiagnostic && x.module === module)
|
||||||
.map((x) => ({value: x.id, label: x.id}))}
|
.map((x) => ({ value: x.id, label: x.id }))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -394,7 +374,7 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
|||||||
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
||||||
"transition duration-300 ease-in-out",
|
"transition duration-300 ease-in-out",
|
||||||
users.filter((u) => g.participants.includes(u.id)).every((u) => assignees.includes(u.id)) &&
|
users.filter((u) => g.participants.includes(u.id)).every((u) => assignees.includes(u.id)) &&
|
||||||
"!bg-mti-purple-light !text-white",
|
"!bg-mti-purple-light !text-white",
|
||||||
)}>
|
)}>
|
||||||
{g.name}
|
{g.name}
|
||||||
</button>
|
</button>
|
||||||
@@ -475,7 +455,7 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
|||||||
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
||||||
"transition duration-300 ease-in-out",
|
"transition duration-300 ease-in-out",
|
||||||
users.filter((u) => g.participants.includes(u.id)).every((u) => teachers.includes(u.id)) &&
|
users.filter((u) => g.participants.includes(u.id)).every((u) => teachers.includes(u.id)) &&
|
||||||
"!bg-mti-purple-light !text-white",
|
"!bg-mti-purple-light !text-white",
|
||||||
)}>
|
)}>
|
||||||
{g.name}
|
{g.name}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import {Module} from "@/interfaces";
|
import { Module } from "@/interfaces";
|
||||||
import {InstructorGender} from "./exam";
|
import { InstructorGender } from "./exam";
|
||||||
import {Stat} from "./user";
|
import { Stat } from "./user";
|
||||||
|
|
||||||
export type UserResults = {[key in Module]: ModuleResult};
|
export type UserResults = { [key in Module]: ModuleResult };
|
||||||
|
|
||||||
interface ModuleResult {
|
interface ModuleResult {
|
||||||
exams: string[];
|
exams: string[];
|
||||||
@@ -22,7 +22,7 @@ export interface Assignment {
|
|||||||
assigner: string;
|
assigner: string;
|
||||||
assignees: string[];
|
assignees: string[];
|
||||||
results: AssignmentResult[];
|
results: AssignmentResult[];
|
||||||
exams: {id: string; module: Module; assignee: string}[];
|
exams: { id: string; module: Module; assignee: string }[];
|
||||||
instructorGender?: InstructorGender;
|
instructorGender?: InstructorGender;
|
||||||
startDate: Date;
|
startDate: Date;
|
||||||
endDate: Date;
|
endDate: Date;
|
||||||
@@ -32,9 +32,8 @@ export interface Assignment {
|
|||||||
// unless start is active, the assignment is not visible to the assignees
|
// unless start is active, the assignment is not visible to the assignees
|
||||||
// start date now works as a limit time to start the exam
|
// start date now works as a limit time to start the exam
|
||||||
start?: boolean;
|
start?: boolean;
|
||||||
autoStartDate?: Date;
|
|
||||||
autoStart?: boolean;
|
autoStart?: boolean;
|
||||||
entity?: string;
|
entity?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AssignmentWithCorporateId = Assignment & {corporateId: string};
|
export type AssignmentWithCorporateId = Assignment & { corporateId: string };
|
||||||
|
|||||||
@@ -6,43 +6,43 @@ import ProgressBar from "@/components/Low/ProgressBar";
|
|||||||
import Select from "@/components/Low/Select";
|
import Select from "@/components/Low/Select";
|
||||||
import Separator from "@/components/Low/Separator";
|
import Separator from "@/components/Low/Separator";
|
||||||
import useExams from "@/hooks/useExams";
|
import useExams from "@/hooks/useExams";
|
||||||
import {useListSearch} from "@/hooks/useListSearch";
|
import { useListSearch } from "@/hooks/useListSearch";
|
||||||
import usePagination from "@/hooks/usePagination";
|
import usePagination from "@/hooks/usePagination";
|
||||||
import {Module} from "@/interfaces";
|
import { Module } from "@/interfaces";
|
||||||
import {EntityWithRoles} from "@/interfaces/entity";
|
import { EntityWithRoles } from "@/interfaces/entity";
|
||||||
import {InstructorGender, Variant} from "@/interfaces/exam";
|
import { InstructorGender, Variant } from "@/interfaces/exam";
|
||||||
import {Assignment} from "@/interfaces/results";
|
import { Assignment } from "@/interfaces/results";
|
||||||
import {Group, User} from "@/interfaces/user";
|
import { Group, User } from "@/interfaces/user";
|
||||||
import {sessionOptions} from "@/lib/session";
|
import { sessionOptions } from "@/lib/session";
|
||||||
import {mapBy, redirect, serialize} from "@/utils";
|
import { mapBy, redirect, serialize } from "@/utils";
|
||||||
import { requestUser } from "@/utils/api";
|
import { requestUser } from "@/utils/api";
|
||||||
import {getAssignment} from "@/utils/assignments.be";
|
import { getAssignment } from "@/utils/assignments.be";
|
||||||
import {getEntitiesWithRoles} from "@/utils/entities.be";
|
import { getEntitiesWithRoles } from "@/utils/entities.be";
|
||||||
import {getGroups, getGroupsByEntities} from "@/utils/groups.be";
|
import { getGroups, getGroupsByEntities } from "@/utils/groups.be";
|
||||||
import {checkAccess, doesEntityAllow, findAllowedEntities} from "@/utils/permissions";
|
import { checkAccess, doesEntityAllow, findAllowedEntities } from "@/utils/permissions";
|
||||||
import {calculateAverageLevel} from "@/utils/score";
|
import { calculateAverageLevel } from "@/utils/score";
|
||||||
import {getEntitiesUsers, getUsers} from "@/utils/users.be";
|
import { getEntitiesUsers, getUsers } from "@/utils/users.be";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import {withIronSessionSsr} from "iron-session/next";
|
import { withIronSessionSsr } from "iron-session/next";
|
||||||
import {capitalize} from "lodash";
|
import { capitalize } from "lodash";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import {useRouter} from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import {generate} from "random-words";
|
import { generate } from "random-words";
|
||||||
import {useEffect, useMemo, useState} from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import ReactDatePicker from "react-datepicker";
|
import ReactDatePicker from "react-datepicker";
|
||||||
import {BsBook, BsCheckCircle, BsChevronLeft, BsClipboard, BsHeadphones, BsMegaphone, BsPen, BsXCircle} from "react-icons/bs";
|
import { BsBook, BsCheckCircle, BsChevronLeft, BsClipboard, BsHeadphones, BsMegaphone, BsPen, BsXCircle } from "react-icons/bs";
|
||||||
import {toast} from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(async ({req, res, params}) => {
|
export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }) => {
|
||||||
const user = await requestUser(req, res)
|
const user = await requestUser(req, res)
|
||||||
if (!user) return redirect("/login")
|
if (!user) return redirect("/login")
|
||||||
|
|
||||||
res.setHeader("Cache-Control", "public, s-maxage=10, stale-while-revalidate=59");
|
res.setHeader("Cache-Control", "public, s-maxage=10, stale-while-revalidate=59");
|
||||||
|
|
||||||
const {id} = params as {id: string};
|
const { id } = params as { id: string };
|
||||||
const entityIDS = mapBy(user.entities, "id") || [];
|
const entityIDS = mapBy(user.entities, "id") || [];
|
||||||
|
|
||||||
const assignment = await getAssignment(id);
|
const assignment = await getAssignment(id);
|
||||||
@@ -59,7 +59,7 @@ export const getServerSideProps = withIronSessionSsr(async ({req, res, params})
|
|||||||
const users = await (checkAccess(user, ["developer", "admin"]) ? getUsers() : getEntitiesUsers(mapBy(allowedEntities, 'id')));
|
const users = await (checkAccess(user, ["developer", "admin"]) ? getUsers() : getEntitiesUsers(mapBy(allowedEntities, 'id')));
|
||||||
const groups = await (checkAccess(user, ["developer", "admin"]) ? getGroups() : getGroupsByEntities(mapBy(allowedEntities, 'id')));
|
const groups = await (checkAccess(user, ["developer", "admin"]) ? getGroups() : getGroupsByEntities(mapBy(allowedEntities, 'id')));
|
||||||
|
|
||||||
return {props: serialize({user, users, entities: allowedEntities, assignment, groups})};
|
return { props: serialize({ user, users, entities: allowedEntities, assignment, groups }) };
|
||||||
}, sessionOptions);
|
}, sessionOptions);
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -72,7 +72,7 @@ interface Props {
|
|||||||
|
|
||||||
const SIZE = 9;
|
const SIZE = 9;
|
||||||
|
|
||||||
export default function AssignmentsPage({assignment, user, users, entities, groups}: Props) {
|
export default function AssignmentsPage({ assignment, user, users, entities, groups }: Props) {
|
||||||
const [selectedModules, setSelectedModules] = useState<Module[]>(assignment.exams.map((e) => e.module));
|
const [selectedModules, setSelectedModules] = useState<Module[]>(assignment.exams.map((e) => e.module));
|
||||||
const [assignees, setAssignees] = useState<string[]>(assignment.assignees);
|
const [assignees, setAssignees] = useState<string[]>(assignment.assignees);
|
||||||
const [teachers, setTeachers] = useState<string[]>(assignment.teachers || []);
|
const [teachers, setTeachers] = useState<string[]>(assignment.teachers || []);
|
||||||
@@ -90,12 +90,11 @@ export default function AssignmentsPage({assignment, user, users, entities, grou
|
|||||||
const [released, setReleased] = useState<boolean>(assignment.released || false);
|
const [released, setReleased] = useState<boolean>(assignment.released || false);
|
||||||
|
|
||||||
const [autoStart, setAutostart] = useState<boolean>(assignment.autoStart || false);
|
const [autoStart, setAutostart] = useState<boolean>(assignment.autoStart || false);
|
||||||
const [autoStartDate, setAutoStartDate] = useState<Date | null>(moment(assignment.autoStartDate).toDate());
|
|
||||||
|
|
||||||
const [useRandomExams, setUseRandomExams] = useState(true);
|
const [useRandomExams, setUseRandomExams] = useState(true);
|
||||||
const [examIDs, setExamIDs] = useState<{id: string; module: Module}[]>([]);
|
const [examIDs, setExamIDs] = useState<{ id: string; module: Module }[]>([]);
|
||||||
|
|
||||||
const {exams} = useExams();
|
const { exams } = useExams();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const classrooms = useMemo(() => groups.filter((e) => e.entity === entity), [entity, groups]);
|
const classrooms = useMemo(() => groups.filter((e) => e.entity === entity), [entity, groups]);
|
||||||
@@ -103,11 +102,11 @@ export default function AssignmentsPage({assignment, user, users, entities, grou
|
|||||||
const userStudents = useMemo(() => users.filter((x) => x.type === "student"), [users]);
|
const userStudents = useMemo(() => users.filter((x) => x.type === "student"), [users]);
|
||||||
const userTeachers = useMemo(() => users.filter((x) => x.type === "teacher"), [users]);
|
const userTeachers = useMemo(() => users.filter((x) => x.type === "teacher"), [users]);
|
||||||
|
|
||||||
const {rows: filteredStudentsRows, renderSearch: renderStudentSearch} = useListSearch([["name"], ["email"]], userStudents);
|
const { rows: filteredStudentsRows, renderSearch: renderStudentSearch } = useListSearch([["name"], ["email"]], userStudents);
|
||||||
const {rows: filteredTeachersRows, renderSearch: renderTeacherSearch} = useListSearch([["name"], ["email"]], userTeachers);
|
const { rows: filteredTeachersRows, renderSearch: renderTeacherSearch } = useListSearch([["name"], ["email"]], userTeachers);
|
||||||
|
|
||||||
const {items: studentRows, renderMinimal: renderStudentPagination} = usePagination(filteredStudentsRows, SIZE);
|
const { items: studentRows, renderMinimal: renderStudentPagination } = usePagination(filteredStudentsRows, SIZE);
|
||||||
const {items: teacherRows, renderMinimal: renderTeacherPagination} = usePagination(filteredTeachersRows, SIZE);
|
const { items: teacherRows, renderMinimal: renderTeacherPagination } = usePagination(filteredTeachersRows, SIZE);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setExamIDs((prev) => prev.filter((x) => selectedModules.includes(x.module)));
|
setExamIDs((prev) => prev.filter((x) => selectedModules.includes(x.module)));
|
||||||
@@ -148,7 +147,6 @@ export default function AssignmentsPage({assignment, user, users, entities, grou
|
|||||||
instructorGender,
|
instructorGender,
|
||||||
released,
|
released,
|
||||||
autoStart,
|
autoStart,
|
||||||
autoStartDate,
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.success(`The assignment "${name}" has been updated successfully!`);
|
toast.success(`The assignment "${name}" has been updated successfully!`);
|
||||||
@@ -316,9 +314,9 @@ export default function AssignmentsPage({assignment, user, users, entities, grou
|
|||||||
<Input type="text" name="name" onChange={(e) => setName(e)} defaultValue={name} label="Assignment Name" required />
|
<Input type="text" name="name" onChange={(e) => setName(e)} defaultValue={name} label="Assignment Name" required />
|
||||||
<Select
|
<Select
|
||||||
label="Entity"
|
label="Entity"
|
||||||
options={entities.map((e) => ({value: e.id, label: e.label}))}
|
options={entities.map((e) => ({ value: e.id, label: e.label }))}
|
||||||
onChange={(v) => setEntity(v ? v.value! : undefined)}
|
onChange={(v) => setEntity(v ? v.value! : undefined)}
|
||||||
defaultValue={{value: entities[0]?.id, label: entities[0]?.label}}
|
defaultValue={{ value: entities[0]?.id, label: entities[0]?.label }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -355,24 +353,6 @@ export default function AssignmentsPage({assignment, user, users, entities, grou
|
|||||||
onChange={(date) => setEndDate(date)}
|
onChange={(date) => setEndDate(date)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{autoStart && (
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<label className="font-normal text-base text-mti-gray-dim">Automatic Start Date *</label>
|
|
||||||
<ReactDatePicker
|
|
||||||
className={clsx(
|
|
||||||
"p-6 w-full min-h-[70px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer",
|
|
||||||
"hover:border-mti-purple tooltip z-10",
|
|
||||||
"transition duration-300 ease-in-out",
|
|
||||||
)}
|
|
||||||
popperClassName="!z-20"
|
|
||||||
filterTime={(date) => moment(date).isSameOrAfter(new Date())}
|
|
||||||
dateFormat="dd/MM/yyyy HH:mm"
|
|
||||||
selected={autoStartDate}
|
|
||||||
showTimeSelect
|
|
||||||
onChange={(date) => setAutoStartDate(date)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedModules.includes("speaking") && (
|
{selectedModules.includes("speaking") && (
|
||||||
@@ -386,9 +366,9 @@ export default function AssignmentsPage({assignment, user, users, entities, grou
|
|||||||
onChange={(value) => (value ? setInstructorGender(value.value as InstructorGender) : null)}
|
onChange={(value) => (value ? setInstructorGender(value.value as InstructorGender) : null)}
|
||||||
disabled={!selectedModules.includes("speaking") || !!assignment}
|
disabled={!selectedModules.includes("speaking") || !!assignment}
|
||||||
options={[
|
options={[
|
||||||
{value: "male", label: "Male"},
|
{ value: "male", label: "Male" },
|
||||||
{value: "female", label: "Female"},
|
{ value: "female", label: "Female" },
|
||||||
{value: "varied", label: "Varied"},
|
{ value: "varied", label: "Varied" },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -412,14 +392,14 @@ export default function AssignmentsPage({assignment, user, users, entities, grou
|
|||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
value
|
value
|
||||||
? setExamIDs((prev) => [
|
? setExamIDs((prev) => [
|
||||||
...prev.filter((x) => x.module !== module),
|
...prev.filter((x) => x.module !== module),
|
||||||
{id: value.value!, module},
|
{ id: value.value!, module },
|
||||||
])
|
])
|
||||||
: setExamIDs((prev) => prev.filter((x) => x.module !== module))
|
: setExamIDs((prev) => prev.filter((x) => x.module !== module))
|
||||||
}
|
}
|
||||||
options={exams
|
options={exams
|
||||||
.filter((x) => !x.isDiagnostic && x.module === module)
|
.filter((x) => !x.isDiagnostic && x.module === module)
|
||||||
.map((x) => ({value: x.id, label: x.id}))}
|
.map((x) => ({ value: x.id, label: x.id }))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -446,7 +426,7 @@ export default function AssignmentsPage({assignment, user, users, entities, grou
|
|||||||
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
||||||
"transition duration-300 ease-in-out",
|
"transition duration-300 ease-in-out",
|
||||||
users.filter((u) => g.participants.includes(u.id)).every((u) => assignees.includes(u.id)) &&
|
users.filter((u) => g.participants.includes(u.id)).every((u) => assignees.includes(u.id)) &&
|
||||||
"!bg-mti-purple-light !text-white",
|
"!bg-mti-purple-light !text-white",
|
||||||
)}>
|
)}>
|
||||||
{g.name}
|
{g.name}
|
||||||
</button>
|
</button>
|
||||||
@@ -510,7 +490,7 @@ export default function AssignmentsPage({assignment, user, users, entities, grou
|
|||||||
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
||||||
"transition duration-300 ease-in-out",
|
"transition duration-300 ease-in-out",
|
||||||
users.filter((u) => g.participants.includes(u.id)).every((u) => teachers.includes(u.id)) &&
|
users.filter((u) => g.participants.includes(u.id)).every((u) => teachers.includes(u.id)) &&
|
||||||
"!bg-mti-purple-light !text-white",
|
"!bg-mti-purple-light !text-white",
|
||||||
)}>
|
)}>
|
||||||
{g.name}
|
{g.name}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -6,37 +6,37 @@ import ProgressBar from "@/components/Low/ProgressBar";
|
|||||||
import Select from "@/components/Low/Select";
|
import Select from "@/components/Low/Select";
|
||||||
import Separator from "@/components/Low/Separator";
|
import Separator from "@/components/Low/Separator";
|
||||||
import useExams from "@/hooks/useExams";
|
import useExams from "@/hooks/useExams";
|
||||||
import {useListSearch} from "@/hooks/useListSearch";
|
import { useListSearch } from "@/hooks/useListSearch";
|
||||||
import usePagination from "@/hooks/usePagination";
|
import usePagination from "@/hooks/usePagination";
|
||||||
import {Module} from "@/interfaces";
|
import { Module } from "@/interfaces";
|
||||||
import {EntityWithRoles, WithEntity} from "@/interfaces/entity";
|
import { EntityWithRoles, WithEntity } from "@/interfaces/entity";
|
||||||
import {InstructorGender, Variant} from "@/interfaces/exam";
|
import { InstructorGender, Variant } from "@/interfaces/exam";
|
||||||
import {Assignment} from "@/interfaces/results";
|
import { Assignment } from "@/interfaces/results";
|
||||||
import {Group, User} from "@/interfaces/user";
|
import { Group, User } from "@/interfaces/user";
|
||||||
import {sessionOptions} from "@/lib/session";
|
import { sessionOptions } from "@/lib/session";
|
||||||
import {mapBy, redirect, serialize} from "@/utils";
|
import { mapBy, redirect, serialize } from "@/utils";
|
||||||
import { requestUser } from "@/utils/api";
|
import { requestUser } from "@/utils/api";
|
||||||
import {getEntitiesWithRoles} from "@/utils/entities.be";
|
import { getEntitiesWithRoles } from "@/utils/entities.be";
|
||||||
import {getGroups, getGroupsByEntities} from "@/utils/groups.be";
|
import { getGroups, getGroupsByEntities } from "@/utils/groups.be";
|
||||||
import {checkAccess, findAllowedEntities} from "@/utils/permissions";
|
import { checkAccess, findAllowedEntities } from "@/utils/permissions";
|
||||||
import {calculateAverageLevel} from "@/utils/score";
|
import { calculateAverageLevel } from "@/utils/score";
|
||||||
import { isAdmin } from "@/utils/users";
|
import { isAdmin } from "@/utils/users";
|
||||||
import {getEntitiesUsers, getUsers} from "@/utils/users.be";
|
import { getEntitiesUsers, getUsers } from "@/utils/users.be";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import {withIronSessionSsr} from "iron-session/next";
|
import { withIronSessionSsr } from "iron-session/next";
|
||||||
import {capitalize} from "lodash";
|
import { capitalize } from "lodash";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import {useRouter} from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import {generate} from "random-words";
|
import { generate } from "random-words";
|
||||||
import {useEffect, useMemo, useState} from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import ReactDatePicker from "react-datepicker";
|
import ReactDatePicker from "react-datepicker";
|
||||||
import {BsBook, BsCheckCircle, BsChevronLeft, BsClipboard, BsHeadphones, BsMegaphone, BsPen, BsXCircle} from "react-icons/bs";
|
import { BsBook, BsCheckCircle, BsChevronLeft, BsClipboard, BsHeadphones, BsMegaphone, BsPen, BsXCircle } from "react-icons/bs";
|
||||||
import {toast} from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(async ({req, res}) => {
|
export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||||
const user = await requestUser(req, res)
|
const user = await requestUser(req, res)
|
||||||
if (!user) return redirect("/login")
|
if (!user) return redirect("/login")
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ export const getServerSideProps = withIronSessionSsr(async ({req, res}) => {
|
|||||||
const users = await (isAdmin(user) ? getUsers() : getEntitiesUsers(mapBy(allowedEntities, 'id')));
|
const users = await (isAdmin(user) ? getUsers() : getEntitiesUsers(mapBy(allowedEntities, 'id')));
|
||||||
const groups = await (isAdmin(user) ? getGroups() : getGroupsByEntities(mapBy(allowedEntities, 'id')));
|
const groups = await (isAdmin(user) ? getGroups() : getGroupsByEntities(mapBy(allowedEntities, 'id')));
|
||||||
|
|
||||||
return {props: serialize({user, users, entities, groups})};
|
return { props: serialize({ user, users, entities, groups }) };
|
||||||
}, sessionOptions);
|
}, sessionOptions);
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -62,7 +62,7 @@ interface Props {
|
|||||||
|
|
||||||
const SIZE = 9;
|
const SIZE = 9;
|
||||||
|
|
||||||
export default function AssignmentsPage({user, users, groups, entities}: Props) {
|
export default function AssignmentsPage({ user, users, groups, entities }: Props) {
|
||||||
const [selectedModules, setSelectedModules] = useState<Module[]>([]);
|
const [selectedModules, setSelectedModules] = useState<Module[]>([]);
|
||||||
const [assignees, setAssignees] = useState<string[]>([]);
|
const [assignees, setAssignees] = useState<string[]>([]);
|
||||||
const [teachers, setTeachers] = useState<string[]>([...(user.type === "teacher" ? [user.id] : [])]);
|
const [teachers, setTeachers] = useState<string[]>([...(user.type === "teacher" ? [user.id] : [])]);
|
||||||
@@ -88,12 +88,11 @@ export default function AssignmentsPage({user, users, groups, entities}: Props)
|
|||||||
const [released, setReleased] = useState<boolean>(false);
|
const [released, setReleased] = useState<boolean>(false);
|
||||||
|
|
||||||
const [autoStart, setAutostart] = useState<boolean>(false);
|
const [autoStart, setAutostart] = useState<boolean>(false);
|
||||||
const [autoStartDate, setAutoStartDate] = useState<Date | null>(new Date());
|
|
||||||
|
|
||||||
const [useRandomExams, setUseRandomExams] = useState(true);
|
const [useRandomExams, setUseRandomExams] = useState(true);
|
||||||
const [examIDs, setExamIDs] = useState<{id: string; module: Module}[]>([]);
|
const [examIDs, setExamIDs] = useState<{ id: string; module: Module }[]>([]);
|
||||||
|
|
||||||
const {exams} = useExams();
|
const { exams } = useExams();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const classrooms = useMemo(() => groups.filter((e) => e.entity?.id === entity), [entity, groups]);
|
const classrooms = useMemo(() => groups.filter((e) => e.entity?.id === entity), [entity, groups]);
|
||||||
@@ -102,11 +101,11 @@ export default function AssignmentsPage({user, users, groups, entities}: Props)
|
|||||||
const userStudents = useMemo(() => allowedUsers.filter((x) => x.type === "student"), [allowedUsers]);
|
const userStudents = useMemo(() => allowedUsers.filter((x) => x.type === "student"), [allowedUsers]);
|
||||||
const userTeachers = useMemo(() => allowedUsers.filter((x) => x.type === "teacher"), [allowedUsers]);
|
const userTeachers = useMemo(() => allowedUsers.filter((x) => x.type === "teacher"), [allowedUsers]);
|
||||||
|
|
||||||
const {rows: filteredStudentsRows, renderSearch: renderStudentSearch} = useListSearch([["name"], ["email"]], userStudents);
|
const { rows: filteredStudentsRows, renderSearch: renderStudentSearch } = useListSearch([["name"], ["email"]], userStudents);
|
||||||
const {rows: filteredTeachersRows, renderSearch: renderTeacherSearch} = useListSearch([["name"], ["email"]], userTeachers);
|
const { rows: filteredTeachersRows, renderSearch: renderTeacherSearch } = useListSearch([["name"], ["email"]], userTeachers);
|
||||||
|
|
||||||
const {items: studentRows, renderMinimal: renderStudentPagination} = usePagination(filteredStudentsRows, SIZE);
|
const { items: studentRows, renderMinimal: renderStudentPagination } = usePagination(filteredStudentsRows, SIZE);
|
||||||
const {items: teacherRows, renderMinimal: renderTeacherPagination} = usePagination(filteredTeachersRows, SIZE);
|
const { items: teacherRows, renderMinimal: renderTeacherPagination } = usePagination(filteredTeachersRows, SIZE);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setExamIDs((prev) => prev.filter((x) => selectedModules.includes(x.module)));
|
setExamIDs((prev) => prev.filter((x) => selectedModules.includes(x.module)));
|
||||||
@@ -148,7 +147,6 @@ export default function AssignmentsPage({user, users, groups, entities}: Props)
|
|||||||
instructorGender,
|
instructorGender,
|
||||||
released,
|
released,
|
||||||
autoStart,
|
autoStart,
|
||||||
autoStartDate,
|
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
toast.success(`The assignment "${name}" has been created successfully!`);
|
toast.success(`The assignment "${name}" has been created successfully!`);
|
||||||
@@ -274,9 +272,9 @@ export default function AssignmentsPage({user, users, groups, entities}: Props)
|
|||||||
<Input type="text" name="name" onChange={(e) => setName(e)} defaultValue={name} label="Assignment Name" required />
|
<Input type="text" name="name" onChange={(e) => setName(e)} defaultValue={name} label="Assignment Name" required />
|
||||||
<Select
|
<Select
|
||||||
label="Entity"
|
label="Entity"
|
||||||
options={entities.map((e) => ({value: e.id, label: e.label}))}
|
options={entities.map((e) => ({ value: e.id, label: e.label }))}
|
||||||
onChange={(v) => setEntity(v ? v.value! : undefined)}
|
onChange={(v) => setEntity(v ? v.value! : undefined)}
|
||||||
defaultValue={{value: entities[0]?.id, label: entities[0]?.label}}
|
defaultValue={{ value: entities[0]?.id, label: entities[0]?.label }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -313,24 +311,6 @@ export default function AssignmentsPage({user, users, groups, entities}: Props)
|
|||||||
onChange={(date) => setEndDate(date)}
|
onChange={(date) => setEndDate(date)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{autoStart && (
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<label className="font-normal text-base text-mti-gray-dim">Automatic Start Date *</label>
|
|
||||||
<ReactDatePicker
|
|
||||||
className={clsx(
|
|
||||||
"p-6 w-full min-h-[70px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer",
|
|
||||||
"hover:border-mti-purple tooltip z-10",
|
|
||||||
"transition duration-300 ease-in-out",
|
|
||||||
)}
|
|
||||||
popperClassName="!z-20"
|
|
||||||
filterTime={(date) => moment(date).isSameOrAfter(new Date())}
|
|
||||||
dateFormat="dd/MM/yyyy HH:mm"
|
|
||||||
selected={autoStartDate}
|
|
||||||
showTimeSelect
|
|
||||||
onChange={(date) => setAutoStartDate(date)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedModules.includes("speaking") && (
|
{selectedModules.includes("speaking") && (
|
||||||
@@ -344,9 +324,9 @@ export default function AssignmentsPage({user, users, groups, entities}: Props)
|
|||||||
onChange={(value) => (value ? setInstructorGender(value.value as InstructorGender) : null)}
|
onChange={(value) => (value ? setInstructorGender(value.value as InstructorGender) : null)}
|
||||||
disabled={!selectedModules.includes("speaking")}
|
disabled={!selectedModules.includes("speaking")}
|
||||||
options={[
|
options={[
|
||||||
{value: "male", label: "Male"},
|
{ value: "male", label: "Male" },
|
||||||
{value: "female", label: "Female"},
|
{ value: "female", label: "Female" },
|
||||||
{value: "varied", label: "Varied"},
|
{ value: "varied", label: "Varied" },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -370,14 +350,14 @@ export default function AssignmentsPage({user, users, groups, entities}: Props)
|
|||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
value
|
value
|
||||||
? setExamIDs((prev) => [
|
? setExamIDs((prev) => [
|
||||||
...prev.filter((x) => x.module !== module),
|
...prev.filter((x) => x.module !== module),
|
||||||
{id: value.value!, module},
|
{ id: value.value!, module },
|
||||||
])
|
])
|
||||||
: setExamIDs((prev) => prev.filter((x) => x.module !== module))
|
: setExamIDs((prev) => prev.filter((x) => x.module !== module))
|
||||||
}
|
}
|
||||||
options={exams
|
options={exams
|
||||||
.filter((x) => !x.isDiagnostic && x.module === module)
|
.filter((x) => !x.isDiagnostic && x.module === module)
|
||||||
.map((x) => ({value: x.id, label: x.id}))}
|
.map((x) => ({ value: x.id, label: x.id }))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -404,7 +384,7 @@ export default function AssignmentsPage({user, users, groups, entities}: Props)
|
|||||||
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
||||||
"transition duration-300 ease-in-out",
|
"transition duration-300 ease-in-out",
|
||||||
users.filter((u) => g.participants.includes(u.id)).every((u) => assignees.includes(u.id)) &&
|
users.filter((u) => g.participants.includes(u.id)).every((u) => assignees.includes(u.id)) &&
|
||||||
"!bg-mti-purple-light !text-white",
|
"!bg-mti-purple-light !text-white",
|
||||||
)}>
|
)}>
|
||||||
{g.name}
|
{g.name}
|
||||||
</button>
|
</button>
|
||||||
@@ -468,7 +448,7 @@ export default function AssignmentsPage({user, users, groups, entities}: Props)
|
|||||||
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
"bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light",
|
||||||
"transition duration-300 ease-in-out",
|
"transition duration-300 ease-in-out",
|
||||||
users.filter((u) => g.participants.includes(u.id)).every((u) => teachers.includes(u.id)) &&
|
users.filter((u) => g.participants.includes(u.id)).every((u) => teachers.includes(u.id)) &&
|
||||||
"!bg-mti-purple-light !text-white",
|
"!bg-mti-purple-light !text-white",
|
||||||
)}>
|
)}>
|
||||||
{g.name}
|
{g.name}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { sessionOptions } from "@/lib/session";
|
|||||||
import useExamStore from "@/stores/examStore";
|
import useExamStore from "@/stores/examStore";
|
||||||
import { filterBy, findBy, mapBy, redirect, serialize } from "@/utils";
|
import { filterBy, findBy, mapBy, redirect, serialize } from "@/utils";
|
||||||
import { requestUser } from "@/utils/api";
|
import { requestUser } from "@/utils/api";
|
||||||
import { activeAssignmentFilter } from "@/utils/assignments";
|
import { activeAssignmentFilter, futureAssignmentFilter } from "@/utils/assignments";
|
||||||
import { getAssignmentsByAssignee } from "@/utils/assignments.be";
|
import { getAssignmentsByAssignee } from "@/utils/assignments.be";
|
||||||
import { getEntitiesWithRoles } from "@/utils/entities.be";
|
import { getEntitiesWithRoles } from "@/utils/entities.be";
|
||||||
import { getExamsByIds } from "@/utils/exams.be";
|
import { getExamsByIds } from "@/utils/exams.be";
|
||||||
@@ -29,7 +29,7 @@ import { uniqBy } from "lodash";
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { BsArrowRepeat } from "react-icons/bs";
|
import { BsArrowRepeat } from "react-icons/bs";
|
||||||
import { ToastContainer } from "react-toastify";
|
import { ToastContainer } from "react-toastify";
|
||||||
|
|
||||||
@@ -74,6 +74,8 @@ const destination = Buffer.from("/official-exam").toString("base64")
|
|||||||
export default function OfficialExam({ user, entities, assignments, sessions, exams }: Props) {
|
export default function OfficialExam({ user, entities, assignments, sessions, exams }: Props) {
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => console.log(assignments), [assignments])
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const state = useExamStore((state) => state);
|
const state = useExamStore((state) => state);
|
||||||
const reload = () => {
|
const reload = () => {
|
||||||
@@ -123,7 +125,11 @@ export default function OfficialExam({ user, entities, assignments, sessions, ex
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const studentAssignments = useMemo(() => assignments.filter(activeAssignmentFilter), [assignments]);
|
const studentAssignments = useMemo(() => [
|
||||||
|
...assignments.filter(activeAssignmentFilter), ...assignments.filter(futureAssignmentFilter)],
|
||||||
|
[assignments]
|
||||||
|
);
|
||||||
|
|
||||||
const assignmentSessions = useMemo(() => sessions.filter(s => mapBy(studentAssignments, 'id').includes(s.assignment?.id || "")), [sessions, studentAssignments])
|
const assignmentSessions = useMemo(() => sessions.filter(s => mapBy(studentAssignments, 'id').includes(s.assignment?.id || "")), [sessions, studentAssignments])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,38 +1,20 @@
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { Assignment } from "@/interfaces/results";
|
import { Assignment } from "@/interfaces/results";
|
||||||
|
|
||||||
// export const futureAssignmentFilter = (a: Assignment) => {
|
|
||||||
// if(a.archived) return false;
|
|
||||||
// if(a.start) return false;
|
|
||||||
|
|
||||||
// const currentDate = moment();
|
|
||||||
// const startDate = moment(a.startDate);
|
|
||||||
// if(currentDate.isAfter(startDate)) return false;
|
|
||||||
// if(a.autoStart && a.autoStartDate) {
|
|
||||||
// return moment(a.autoStartDate).isAfter(currentDate);
|
|
||||||
// }
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
export const futureAssignmentFilter = (a: Assignment) => {
|
export const futureAssignmentFilter = (a: Assignment) => {
|
||||||
const currentDate = moment();
|
const currentDate = moment();
|
||||||
if (moment(a.endDate).isBefore(currentDate)) return false;
|
|
||||||
if (a.archived) return false;
|
if (a.archived) return false;
|
||||||
|
if (moment(a.endDate).isBefore(currentDate)) return false;
|
||||||
|
if (a.autoStart && moment(a.startDate).isBefore(currentDate)) return false;
|
||||||
|
|
||||||
if (a.autoStart && a.autoStartDate && moment(a.autoStartDate).isBefore(currentDate)) return false;
|
return !a.start;
|
||||||
|
|
||||||
if (!a.start) {
|
|
||||||
if (moment(a.startDate).isBefore(currentDate)) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const pastAssignmentFilter = (a: Assignment) => {
|
export const pastAssignmentFilter = (a: Assignment) => {
|
||||||
const currentDate = moment();
|
const currentDate = moment();
|
||||||
if (a.archived) {
|
|
||||||
return false;
|
if (a.archived) return false;
|
||||||
}
|
|
||||||
|
|
||||||
return moment(a.endDate).isBefore(currentDate);
|
return moment(a.endDate).isBefore(currentDate);
|
||||||
}
|
}
|
||||||
@@ -44,25 +26,11 @@ export const activeAssignmentFilter = (a: Assignment) => {
|
|||||||
if (moment(a.endDate).isBefore(currentDate) || a.archived) return false;
|
if (moment(a.endDate).isBefore(currentDate) || a.archived) return false;
|
||||||
|
|
||||||
if (a.start) return true;
|
if (a.start) return true;
|
||||||
if (a.autoStart && a.autoStartDate) return moment(a.autoStartDate).isBefore(currentDate);
|
if (a.autoStart) return currentDate.isAfter(moment(a.startDate));
|
||||||
|
|
||||||
return currentDate.isAfter(moment(a.startDate));
|
return false
|
||||||
};
|
};
|
||||||
|
|
||||||
// export const unstartedAssignmentFilter = (a: Assignment) => {
|
|
||||||
// const currentDate = moment();
|
|
||||||
// if(moment(a.endDate).isBefore(currentDate)) return false;
|
|
||||||
// if(a.archived) return false;
|
|
||||||
|
|
||||||
// if(a.autoStart && a.autoStartDate && moment(a.autoStartDate).isBefore(currentDate)) return false;
|
|
||||||
|
|
||||||
// if(!a.start) {
|
|
||||||
// if(moment(a.startDate).isBefore(currentDate)) return false;
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
export const startHasExpiredAssignmentFilter = (a: Assignment) => {
|
export const startHasExpiredAssignmentFilter = (a: Assignment) => {
|
||||||
const currentDate = moment();
|
const currentDate = moment();
|
||||||
if (a.archived) return false;
|
if (a.archived) return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user