From a7c1ea0409a4246f534372adaab741b9a48a6d82 Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Tue, 3 Sep 2024 22:56:43 +0100 Subject: [PATCH] Imporvements on started management of assignment --- src/dashboards/AssignmentView.tsx | 694 +++++++++++++---------- src/dashboards/views/AssignmentsPage.tsx | 359 +++++++----- src/utils/assignments.ts | 11 + 3 files changed, 630 insertions(+), 434 deletions(-) diff --git a/src/dashboards/AssignmentView.tsx b/src/dashboards/AssignmentView.tsx index 03f5baff..7426b19d 100644 --- a/src/dashboards/AssignmentView.tsx +++ b/src/dashboards/AssignmentView.tsx @@ -2,329 +2,435 @@ import Button from "@/components/Low/Button"; import ProgressBar from "@/components/Low/ProgressBar"; import Modal from "@/components/Modal"; import useUsers from "@/hooks/useUsers"; -import {Module} from "@/interfaces"; -import {Assignment} from "@/interfaces/results"; -import {Stat, User} from "@/interfaces/user"; +import { Module } from "@/interfaces"; +import { Assignment } from "@/interfaces/results"; +import { Stat, User } from "@/interfaces/user"; import useExamStore from "@/stores/examStore"; -import {getExamById} from "@/utils/exams"; -import {sortByModule} from "@/utils/moduleUtils"; -import {calculateBandScore} from "@/utils/score"; -import {convertToUserSolutions} from "@/utils/stats"; -import {getUserName} from "@/utils/users"; +import { getExamById } from "@/utils/exams"; +import { sortByModule } from "@/utils/moduleUtils"; +import { calculateBandScore } from "@/utils/score"; +import { convertToUserSolutions } from "@/utils/stats"; +import { getUserName } from "@/utils/users"; import axios from "axios"; import clsx from "clsx"; -import {capitalize, uniqBy} from "lodash"; +import { capitalize, uniqBy } from "lodash"; import moment from "moment"; -import {useRouter} from "next/router"; -import {BsBook, BsClipboard, BsHeadphones, BsMegaphone, BsPen} from "react-icons/bs"; -import {toast} from "react-toastify"; +import { useRouter } from "next/router"; +import { + BsBook, + BsClipboard, + BsHeadphones, + BsMegaphone, + BsPen, +} from "react-icons/bs"; +import { toast } from "react-toastify"; +import { activeAssignmentFilter } from "@/utils/assignments"; interface Props { - isOpen: boolean; - assignment?: Assignment; - onClose: () => void; + isOpen: boolean; + assignment?: Assignment; + onClose: () => void; } -export default function AssignmentView({isOpen, assignment, onClose}: Props) { - const {users} = useUsers(); - const router = useRouter(); +export default function AssignmentView({ isOpen, assignment, onClose }: Props) { + const { users } = useUsers(); + const router = useRouter(); - const setExams = useExamStore((state) => state.setExams); - const setShowSolutions = useExamStore((state) => state.setShowSolutions); - const setUserSolutions = useExamStore((state) => state.setUserSolutions); - const setSelectedModules = useExamStore((state) => state.setSelectedModules); + const setExams = useExamStore((state) => state.setExams); + const setShowSolutions = useExamStore((state) => state.setShowSolutions); + const setUserSolutions = useExamStore((state) => state.setUserSolutions); + const setSelectedModules = useExamStore((state) => state.setSelectedModules); - const deleteAssignment = async () => { - if (!confirm("Are you sure you want to delete this assignment?")) return; + const deleteAssignment = async () => { + if (!confirm("Are you sure you want to delete this assignment?")) return; - axios - .delete(`/api/assignments/${assignment?.id}`) - .then(() => toast.success(`Successfully deleted the assignment "${assignment?.name}".`)) - .catch(() => toast.error("Something went wrong, please try again later.")) - .finally(onClose); - }; + axios + .delete(`/api/assignments/${assignment?.id}`) + .then(() => + toast.success( + `Successfully deleted the assignment "${assignment?.name}".` + ) + ) + .catch(() => toast.error("Something went wrong, please try again later.")) + .finally(onClose); + }; - const startAssignment = () => { - if (assignment) { - axios - .post(`/api/assignments/${assignment.id}/start`) - .then(() => { - toast.success(`The assignment "${assignment.name}" has been started successfully!`); - }) - .catch((e) => { - console.log(e); - toast.error("Something went wrong, please try again later!"); - }); - } - }; + const startAssignment = () => { + if (assignment) { + axios + .post(`/api/assignments/${assignment.id}/start`) + .then(() => { + toast.success( + `The assignment "${assignment.name}" has been started successfully!` + ); + }) + .catch((e) => { + console.log(e); + toast.error("Something went wrong, please try again later!"); + }); + } + }; - const formatTimestamp = (timestamp: string) => { - const date = moment(parseInt(timestamp)); - const formatter = "YYYY/MM/DD - HH:mm"; + const formatTimestamp = (timestamp: string) => { + const date = moment(parseInt(timestamp)); + const formatter = "YYYY/MM/DD - HH:mm"; - return date.format(formatter); - }; + return date.format(formatter); + }; - const calculateAverageModuleScore = (module: Module) => { - if (!assignment) return -1; + const calculateAverageModuleScore = (module: Module) => { + if (!assignment) return -1; - const resultModuleBandScores = assignment.results.map((r) => { - const moduleStats = r.stats.filter((s) => s.module === module); + const resultModuleBandScores = assignment.results.map((r) => { + const moduleStats = r.stats.filter((s) => s.module === module); - const correct = moduleStats.reduce((acc, curr) => acc + curr.score.correct, 0); - const total = moduleStats.reduce((acc, curr) => acc + curr.score.total, 0); - return calculateBandScore(correct, total, module, r.type); - }); + const correct = moduleStats.reduce( + (acc, curr) => acc + curr.score.correct, + 0 + ); + const total = moduleStats.reduce( + (acc, curr) => acc + curr.score.total, + 0 + ); + return calculateBandScore(correct, total, module, r.type); + }); - return resultModuleBandScores.length === 0 ? -1 : resultModuleBandScores.reduce((acc, curr) => acc + curr, 0) / assignment.results.length; - }; + return resultModuleBandScores.length === 0 + ? -1 + : resultModuleBandScores.reduce((acc, curr) => acc + curr, 0) / + assignment.results.length; + }; - const aggregateScoresByModule = (stats: Stat[]): {module: Module; total: number; missing: number; correct: number}[] => { - const scores: { - [key in Module]: {total: number; missing: number; correct: number}; - } = { - reading: { - total: 0, - correct: 0, - missing: 0, - }, - listening: { - total: 0, - correct: 0, - missing: 0, - }, - writing: { - total: 0, - correct: 0, - missing: 0, - }, - speaking: { - total: 0, - correct: 0, - missing: 0, - }, - level: { - total: 0, - correct: 0, - missing: 0, - }, - }; + const aggregateScoresByModule = ( + stats: Stat[] + ): { module: Module; total: number; missing: number; correct: number }[] => { + const scores: { + [key in Module]: { total: number; missing: number; correct: number }; + } = { + reading: { + total: 0, + correct: 0, + missing: 0, + }, + listening: { + total: 0, + correct: 0, + missing: 0, + }, + writing: { + total: 0, + correct: 0, + missing: 0, + }, + speaking: { + total: 0, + correct: 0, + missing: 0, + }, + level: { + total: 0, + correct: 0, + missing: 0, + }, + }; - stats.forEach((x) => { - scores[x.module!] = { - total: scores[x.module!].total + x.score.total, - correct: scores[x.module!].correct + x.score.correct, - missing: scores[x.module!].missing + x.score.missing, - }; - }); + stats.forEach((x) => { + scores[x.module!] = { + total: scores[x.module!].total + x.score.total, + correct: scores[x.module!].correct + x.score.correct, + missing: scores[x.module!].missing + x.score.missing, + }; + }); - return Object.keys(scores) - .filter((x) => scores[x as Module].total > 0) - .map((x) => ({module: x as Module, ...scores[x as Module]})); - }; + return Object.keys(scores) + .filter((x) => scores[x as Module].total > 0) + .map((x) => ({ module: x as Module, ...scores[x as Module] })); + }; - const customContent = (stats: Stat[], user: string, focus: "academic" | "general") => { - const correct = stats.reduce((accumulator, current) => accumulator + current.score.correct, 0); - const total = stats.reduce((accumulator, current) => accumulator + current.score.total, 0); - const aggregatedScores = aggregateScoresByModule(stats).filter((x) => x.total > 0); + const customContent = ( + stats: Stat[], + user: string, + focus: "academic" | "general" + ) => { + const correct = stats.reduce( + (accumulator, current) => accumulator + current.score.correct, + 0 + ); + const total = stats.reduce( + (accumulator, current) => accumulator + current.score.total, + 0 + ); + const aggregatedScores = aggregateScoresByModule(stats).filter( + (x) => x.total > 0 + ); - const aggregatedLevels = aggregatedScores.map((x) => ({ - module: x.module, - level: calculateBandScore(x.correct, x.total, x.module, focus), - })); + const aggregatedLevels = aggregatedScores.map((x) => ({ + module: x.module, + level: calculateBandScore(x.correct, x.total, x.module, focus), + })); - const timeSpent = stats[0].timeSpent; + const timeSpent = stats[0].timeSpent; - const selectExam = () => { - const examPromises = uniqBy(stats, "exam").map((stat) => getExamById(stat.module, stat.exam)); + const selectExam = () => { + const examPromises = uniqBy(stats, "exam").map((stat) => + getExamById(stat.module, stat.exam) + ); - Promise.all(examPromises).then((exams) => { - if (exams.every((x) => !!x)) { - setUserSolutions(convertToUserSolutions(stats)); - setShowSolutions(true); - setExams(exams.map((x) => x!).sort(sortByModule)); - setSelectedModules( - exams - .map((x) => x!) - .sort(sortByModule) - .map((x) => x!.module), - ); - router.push("/exercises"); - } - }); - }; + Promise.all(examPromises).then((exams) => { + if (exams.every((x) => !!x)) { + setUserSolutions(convertToUserSolutions(stats)); + setShowSolutions(true); + setExams(exams.map((x) => x!).sort(sortByModule)); + setSelectedModules( + exams + .map((x) => x!) + .sort(sortByModule) + .map((x) => x!.module) + ); + router.push("/exercises"); + } + }); + }; - const content = ( - <> -
-
- {formatTimestamp(stats[0].date.toString())} - {timeSpent && ( - <> - - {Math.floor(timeSpent / 60)} minutes - - )} -
- = 0.7 && "text-mti-purple", - correct / total >= 0.3 && correct / total < 0.7 && "text-mti-red", - correct / total < 0.3 && "text-mti-rose", - )}> - Level{" "} - {(aggregatedLevels.reduce((accumulator, current) => accumulator + current.level, 0) / aggregatedLevels.length).toFixed(1)} - -
+ const content = ( + <> +
+
+ + {formatTimestamp(stats[0].date.toString())} + + {timeSpent && ( + <> + + + {Math.floor(timeSpent / 60)} minutes + + + )} +
+ = 0.7 && "text-mti-purple", + correct / total >= 0.3 && correct / total < 0.7 && "text-mti-red", + correct / total < 0.3 && "text-mti-rose" + )} + > + Level{" "} + {( + aggregatedLevels.reduce( + (accumulator, current) => accumulator + current.level, + 0 + ) / aggregatedLevels.length + ).toFixed(1)} + +
-
-
- {aggregatedLevels.map(({module, level}) => ( -
- {module === "reading" && } - {module === "listening" && } - {module === "writing" && } - {module === "speaking" && } - {module === "level" && } - {level.toFixed(1)} -
- ))} -
-
- - ); +
+
+ {aggregatedLevels.map(({ module, level }) => ( +
+ {module === "reading" && } + {module === "listening" && } + {module === "writing" && } + {module === "speaking" && } + {module === "level" && } + {level.toFixed(1)} +
+ ))} +
+
+ + ); - return ( -
- - {(() => { - const student = users.find((u) => u.id === user); - return `${student?.name} (${student?.email})`; - })()} - -
= 0.7 && "hover:border-mti-purple", - correct / total >= 0.3 && correct / total < 0.7 && "hover:border-mti-red", - correct / total < 0.3 && "hover:border-mti-rose", - )} - onClick={selectExam} - role="button"> - {content} -
-
= 0.7 && "hover:border-mti-purple", - correct / total >= 0.3 && correct / total < 0.7 && "hover:border-mti-red", - correct / total < 0.3 && "hover:border-mti-rose", - )} - data-tip="Your screen size is too small to view previous exams." - role="button"> - {content} -
-
- ); - }; + return ( +
+ + {(() => { + const student = users.find((u) => u.id === user); + return `${student?.name} (${student?.email})`; + })()} + +
= 0.7 && "hover:border-mti-purple", + correct / total >= 0.3 && + correct / total < 0.7 && + "hover:border-mti-red", + correct / total < 0.3 && "hover:border-mti-rose" + )} + onClick={selectExam} + role="button" + > + {content} +
+
= 0.7 && "hover:border-mti-purple", + correct / total >= 0.3 && + correct / total < 0.7 && + "hover:border-mti-red", + correct / total < 0.3 && "hover:border-mti-rose" + )} + data-tip="Your screen size is too small to view previous exams." + role="button" + > + {content} +
+
+ ); + }; - return ( - -
- -
-
- Start Date: {moment(assignment?.startDate).format("DD/MM/YY, HH:mm")} - End Date: {moment(assignment?.endDate).format("DD/MM/YY, HH:mm")} -
-
- - Assignees:{" "} - {users - .filter((u) => assignment?.assignees.includes(u.id)) - .map((u) => `${u.name} (${u.email})`) - .join(", ")} - - Assigner: {getUserName(users.find((x) => x.id === assignment?.assigner))} -
-
-
- Average Scores -
- {assignment && - uniqBy(assignment.exams, (x) => x.module).map(({module}) => ( -
- {module === "reading" && } - {module === "listening" && } - {module === "writing" && } - {module === "speaking" && } - {module === "level" && } - {calculateAverageModuleScore(module) > -1 && ( - {calculateAverageModuleScore(module).toFixed(1)} - )} -
- ))} -
-
-
- - Results ({assignment?.results.length}/{assignment?.assignees.length}) - -
- {assignment && assignment?.results.length > 0 && ( -
- {assignment.results.map((r) => customContent(r.stats, r.user, r.type))} -
- )} - {assignment && assignment?.results.length === 0 && No results yet...} -
-
+ const shouldRenderStart = () => { + if (assignment) { + if (activeAssignmentFilter(assignment)) { + return false; + } -
- {assignment && (assignment.results.length === assignment.assignees.length || moment().isAfter(moment(assignment.endDate))) && ( - - )} - {assignment && (assignment.results.length === 0 || moment().isAfter(moment(assignment.startDate))) && ( - - )} - -
-
-
- ); + return assignment.results.length === 0; + } + + return false; + }; + + return ( + +
+ +
+
+ + Start Date:{" "} + {moment(assignment?.startDate).format("DD/MM/YY, HH:mm")} + + + End Date: {moment(assignment?.endDate).format("DD/MM/YY, HH:mm")} + +
+
+ + Assignees:{" "} + {users + .filter((u) => assignment?.assignees.includes(u.id)) + .map((u) => `${u.name} (${u.email})`) + .join(", ")} + + + Assigner:{" "} + {getUserName(users.find((x) => x.id === assignment?.assigner))} + +
+
+
+ Average Scores +
+ {assignment && + uniqBy(assignment.exams, (x) => x.module).map(({ module }) => ( +
+ {module === "reading" && } + {module === "listening" && ( + + )} + {module === "writing" && } + {module === "speaking" && } + {module === "level" && } + {calculateAverageModuleScore(module) > -1 && ( + + {calculateAverageModuleScore(module).toFixed(1)} + + )} +
+ ))} +
+
+
+ + Results ({assignment?.results.length}/{assignment?.assignees.length} + ) + +
+ {assignment && assignment?.results.length > 0 && ( +
+ {assignment.results.map((r) => + customContent(r.stats, r.user, r.type) + )} +
+ )} + {assignment && assignment?.results.length === 0 && ( + No results yet... + )} +
+
+ +
+ {assignment && + (assignment.results.length === assignment.assignees.length || + moment().isAfter(moment(assignment.endDate))) && ( + + )} + {/** if the assignment is not deemed as active yet, display start */} + {shouldRenderStart() && ( + + )} + +
+
+
+ ); } diff --git a/src/dashboards/views/AssignmentsPage.tsx b/src/dashboards/views/AssignmentsPage.tsx index c6ff9a10..19e0a8d0 100644 --- a/src/dashboards/views/AssignmentsPage.tsx +++ b/src/dashboards/views/AssignmentsPage.tsx @@ -1,150 +1,229 @@ -import {Assignment} from "@/interfaces/results"; -import {CorporateUser, Group, User} from "@/interfaces/user"; -import {getUserCompanyName} from "@/resources/user"; -import {activeAssignmentFilter, archivedAssignmentFilter, futureAssignmentFilter, pastAssignmentFilter} from "@/utils/assignments"; +import { Assignment } from "@/interfaces/results"; +import { CorporateUser, Group, User } from "@/interfaces/user"; +import { getUserCompanyName } from "@/resources/user"; +import { + activeAssignmentFilter, + archivedAssignmentFilter, + futureAssignmentFilter, + pastAssignmentFilter, + unstartedAssignmentFilter, +} from "@/utils/assignments"; import clsx from "clsx"; -import {groupBy} from "lodash"; -import {useState} from "react"; -import {BsArrowLeft, BsArrowRepeat, BsPlus} from "react-icons/bs"; +import { groupBy } from "lodash"; +import { useState } from "react"; +import { BsArrowLeft, BsArrowRepeat, BsPlus } from "react-icons/bs"; import AssignmentCard from "../AssignmentCard"; import AssignmentCreator from "../AssignmentCreator"; import AssignmentView from "../AssignmentView"; interface Props { - assignments: Assignment[]; - corporateAssignments?: ({corporate?: CorporateUser} & Assignment)[]; - groups: Group[]; - users: User[]; - isLoading: boolean; - user: User; - onBack: () => void; - reloadAssignments: () => void; + assignments: Assignment[]; + corporateAssignments?: ({ corporate?: CorporateUser } & Assignment)[]; + groups: Group[]; + users: User[]; + isLoading: boolean; + user: User; + onBack: () => void; + reloadAssignments: () => void; } -export default function AssignmentsPage({assignments, corporateAssignments, user, groups, users, isLoading, onBack, reloadAssignments}: Props) { - const [selectedAssignment, setSelectedAssignment] = useState(); - const [isCreatingAssignment, setIsCreatingAssignment] = useState(false); +export default function AssignmentsPage({ + assignments, + corporateAssignments, + user, + groups, + users, + isLoading, + onBack, + reloadAssignments, +}: Props) { + const [selectedAssignment, setSelectedAssignment] = useState(); + const [isCreatingAssignment, setIsCreatingAssignment] = useState(false); - return ( - <> - { - setSelectedAssignment(undefined); - setIsCreatingAssignment(false); - reloadAssignments(); - }} - assignment={selectedAssignment} - /> - {/** I'll be using this is creating assingment as a workaround for a key to trigger a new rendering */} - {isCreatingAssignment && { - setIsCreatingAssignment(false); - setSelectedAssignment(undefined); - reloadAssignments(); - }} - />} -
-
- - Back -
-
- Reload - -
-
-
- Active Assignments Status -
- - Total: {assignments.filter(activeAssignmentFilter).reduce((acc, curr) => acc + curr.results.length, 0)}/ - {assignments.filter(activeAssignmentFilter).reduce((acc, curr) => curr.exams.length + acc, 0)} - - {Object.keys(groupBy(corporateAssignments, (x) => x.corporate?.id)).map((x) => ( -
- {getUserCompanyName(users.find((u) => u.id === x)!, users, groups)}: - - {groupBy(corporateAssignments, (x) => x.corporate?.id)[x].reduce((acc, curr) => curr.results.length + acc, 0)}/ - {groupBy(corporateAssignments, (x) => x.corporate?.id)[x].reduce((acc, curr) => curr.exams.length + acc, 0)} - -
- ))} -
-
-
-

Active Assignments ({assignments.filter(activeAssignmentFilter).length})

-
- {assignments.filter(activeAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} key={a.id} /> - ))} -
-
-
-

Planned Assignments ({assignments.filter(futureAssignmentFilter).length})

-
-
setIsCreatingAssignment(true)} - className="w-[250px] h-[200px] flex flex-col gap-2 items-center justify-center bg-white hover:bg-mti-purple-ultralight text-mti-purple-light hover:text-mti-purple-dark border border-mti-gray-platinum hover:drop-shadow p-4 cursor-pointer rounded-xl transition ease-in-out duration-300"> - - New Assignment -
- {assignments.filter(futureAssignmentFilter).map((a) => ( - { - setSelectedAssignment(a); - setIsCreatingAssignment(true); - }} - key={a.id} - /> - ))} -
-
-
-

Past Assignments ({assignments.filter(pastAssignmentFilter).length})

-
- {assignments.filter(pastAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - allowDownload - reload={reloadAssignments} - allowArchive - allowExcelDownload - /> - ))} -
-
-
-

Archived Assignments ({assignments.filter(archivedAssignmentFilter).length})

-
- {assignments.filter(archivedAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - allowDownload - reload={reloadAssignments} - allowUnarchive - allowExcelDownload - /> - ))} -
-
- - ); + const unstartedAssignments = assignments.filter(unstartedAssignmentFilter); + + const displayAssignmentView = !!selectedAssignment && !isCreatingAssignment; + + return ( + <> + {displayAssignmentView && ( + { + setSelectedAssignment(undefined); + setIsCreatingAssignment(false); + reloadAssignments(); + }} + assignment={selectedAssignment} + /> + )} + {/** I'll be using this is creating assingment as a workaround for a key to trigger a new rendering */} + {isCreatingAssignment && ( + { + setIsCreatingAssignment(false); + setSelectedAssignment(undefined); + reloadAssignments(); + }} + /> + )} +
+
+ + Back +
+
+ Reload + +
+
+
+ Active Assignments Status +
+ + Total:{" "} + {assignments + .filter(activeAssignmentFilter) + .reduce((acc, curr) => acc + curr.results.length, 0)} + / + {assignments + .filter(activeAssignmentFilter) + .reduce((acc, curr) => curr.exams.length + acc, 0)} + + {Object.keys( + groupBy(corporateAssignments, (x) => x.corporate?.id) + ).map((x) => ( +
+ + {getUserCompanyName( + users.find((u) => u.id === x)!, + users, + groups + )} + :{" "} + + + {groupBy(corporateAssignments, (x) => x.corporate?.id)[ + x + ].reduce((acc, curr) => curr.results.length + acc, 0)} + / + {groupBy(corporateAssignments, (x) => x.corporate?.id)[ + x + ].reduce((acc, curr) => curr.exams.length + acc, 0)} + +
+ ))} +
+
+
+

+ Active Assignments ( + {assignments.filter(activeAssignmentFilter).length}) +

+
+ {assignments.filter(activeAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} + key={a.id} + /> + ))} +
+
+
+

+ Active Assignments Pending Start ({unstartedAssignments.length}) +

+
+ {unstartedAssignments.map((a) => ( + setSelectedAssignment(a)} + key={a.id} + /> + ))} +
+
+
+

+ Planned Assignments ( + {assignments.filter(futureAssignmentFilter).length}) +

+
+
setIsCreatingAssignment(true)} + className="w-[250px] h-[200px] flex flex-col gap-2 items-center justify-center bg-white hover:bg-mti-purple-ultralight text-mti-purple-light hover:text-mti-purple-dark border border-mti-gray-platinum hover:drop-shadow p-4 cursor-pointer rounded-xl transition ease-in-out duration-300" + > + + New Assignment +
+ {assignments.filter(futureAssignmentFilter).map((a) => ( + { + setSelectedAssignment(a); + setIsCreatingAssignment(true); + }} + key={a.id} + /> + ))} +
+
+
+

+ Past Assignments ({assignments.filter(pastAssignmentFilter).length}) +

+
+ {assignments.filter(pastAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} + key={a.id} + allowDownload + reload={reloadAssignments} + allowArchive + allowExcelDownload + /> + ))} +
+
+
+

+ Archived Assignments ( + {assignments.filter(archivedAssignmentFilter).length}) +

+
+ {assignments.filter(archivedAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} + key={a.id} + allowDownload + reload={reloadAssignments} + allowUnarchive + allowExcelDownload + /> + ))} +
+
+ + ); } diff --git a/src/utils/assignments.ts b/src/utils/assignments.ts index a4584981..6bfc6fa5 100644 --- a/src/utils/assignments.ts +++ b/src/utils/assignments.ts @@ -38,3 +38,14 @@ export const activeAssignmentFilter = (a: Assignment) => { 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) return true; + return false; +} \ No newline at end of file