diff --git a/src/components/planner/sidebar/CoursesController/ClassItem.tsx b/src/components/planner/sidebar/CoursesController/ClassItem.tsx index 13769b51..b8bc0332 100644 --- a/src/components/planner/sidebar/CoursesController/ClassItem.tsx +++ b/src/components/planner/sidebar/CoursesController/ClassItem.tsx @@ -1,8 +1,8 @@ -import { useContext, useMemo } from 'react' +import { useContext } from 'react' import { ClassInfo } from '../../../../@types/index' import { DropdownMenuCheckboxItem } from '../../../ui/dropdown-menu' import { ExclamationTriangleIcon } from '@heroicons/react/20/solid' -import { conflictsSeverity, schedulesConflict } from '../../../../utils' +import { classesConflictSeverity } from '../../../../utils' import MultipleOptionsContext from '../../../../contexts/MultipleOptionsContext' import CourseContext from '../../../../contexts/CourseContext' @@ -10,7 +10,6 @@ import CourseContext from '../../../../contexts/CourseContext' type Props = { course_id: number, classInfo: ClassInfo - conflict?: boolean onSelect?: () => void onMouseEnter?: () => void onMouseLeave?: () => void @@ -29,26 +28,26 @@ const ClassItem = ({ course_id, classInfo, onSelect, onMouseEnter, onMouseLeave onSelect(); } - const conflict: number = useMemo(() => { - const classes: ClassInfo[] = [] + const conflictSeverity = () => { + const chosenCourses = multipleOptions[selectedOption].course_options.filter( + (option) => option.course_id !== course_id + ); - for (const course_option of multipleOptions[selectedOption].course_options) { - if (course_option.picked_class_id && course_option.course_id !== course_id) { - const pickedCourse = pickedCourses.find(co => co.id === course_option.course_id); - // retrieve class with the picked class id of the course option - const pickedClass = pickedCourse.classes.find(c => c.id === course_option.picked_class_id); + const otherClasses = []; + chosenCourses.forEach((option) => { + const courseInfo = pickedCourses.find((course) => course.id === option.course_id); + const pickedClass = courseInfo.classes.find((classInfo) => classInfo.id === option.picked_class_id); - classes.push(pickedClass); - } + if (pickedClass) otherClasses.push(pickedClass); + }); + + let maxSeverity = 0; + for (const otherClass of otherClasses) { + maxSeverity = Math.max(maxSeverity, classesConflictSeverity(classInfo, otherClass)); } - for (const pickedClass of classes) - for (const slot1 of pickedClass.slots) - for (const slot2 of classInfo.slots) - if (schedulesConflict(slot1, slot2)) { - return conflictsSeverity(slot1, slot2); - } - }, []); + return maxSeverity; + } return ( (
{slot.lesson_type} - {/* {convertWeekday(slot.day)} */} - {/* {getLessonBoxTime(slot)} */} {slot.location} {slot.professors.map((professor) => professor.acronym).join(', ')} @@ -72,7 +69,7 @@ const ClassItem = ({ course_id, classInfo, onSelect, onMouseEnter, onMouseLeave ))}
-
) } diff --git a/src/components/planner/sidebar/CoursesController/ClassSelectorDropdownController.tsx b/src/components/planner/sidebar/CoursesController/ClassSelectorDropdownController.tsx index a5d42203..bf064d62 100644 --- a/src/components/planner/sidebar/CoursesController/ClassSelectorDropdownController.tsx +++ b/src/components/planner/sidebar/CoursesController/ClassSelectorDropdownController.tsx @@ -4,7 +4,7 @@ import { ClassInfo, CourseInfo, CourseOption, ProfessorInfo } from "../../../../ import StorageAPI from "../../../../api/storage"; import CourseContext from "../../../../contexts/CourseContext"; import MultipleOptionsContext from "../../../../contexts/MultipleOptionsContext"; -import { getAllPickedSlots, schedulesConflict, teacherIdsFromCourseInfo, uniqueTeachersFromCourseInfo } from "../../../../utils"; +import { teacherIdsFromCourseInfo, uniqueTeachersFromCourseInfo } from "../../../../utils"; import { Desert } from "../../../svgs"; import { DropdownMenuGroup, DropdownMenuItem, DropdownMenuPortal, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger } from "../../../ui/dropdown-menu"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../../ui/tabs"; @@ -157,13 +157,6 @@ const ClassSelectorDropdownController = ({ setMultipleOptions(newMultipleOptions) } - // Checks if any of the selected classes have time conflicts with the classInfo - // This is used to display a warning icon in each class of the dropdown in case of conflicts - const timesCollideWithSelected = (classInfo: ClassInfo) => { - const pickedSlots = getAllPickedSlots(pickedCourses, multipleOptions[selectedOption]) - return pickedSlots.some((slot) => classInfo.slots.some((currentSlot) => schedulesConflict(slot, currentSlot))) - } - return <>
{course.classes === null ? ( @@ -226,7 +219,6 @@ const ClassSelectorDropdownController = ({ key={`schedule-${classInfo.name}`} course_id={course.id} classInfo={classInfo} - conflict={timesCollideWithSelected(classInfo)} onSelect={() => { setSelectedClassId(classInfo.id) setPreview(null) @@ -260,7 +252,6 @@ const ClassSelectorDropdownController = ({ key={`schedule-${classInfo.name}`} course_id={course.id} classInfo={classInfo} - conflict={timesCollideWithSelected(classInfo)} onSelect={() => { setSelectedClassId(classInfo.id) setPreview(null) diff --git a/src/utils/index.ts b/src/utils/index.ts index 9a26ab6f..af71ab82 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,6 +1,6 @@ import config from '../config/prod.json' import dev_config from '../config/local.json' -import { CourseInfo, CourseOption, SlotInfo, MultipleOptions, Option, PickedCourses, ProfessorInfo } from '../@types' +import { CourseInfo, CourseOption, SlotInfo, MultipleOptions, Option, PickedCourses, ProfessorInfo, ClassInfo } from '../@types' import { type ClassValue, clsx } from 'clsx' import { twMerge } from 'tailwind-merge' import Plausible from 'plausible-tracker' @@ -77,6 +77,20 @@ const conflictsSeverity = (first: SlotInfo, second: SlotInfo): number => { return (isMandatory(first) && isMandatory(second)) ? 2 : 1; } +const classesConflictSeverity = (first: ClassInfo, second: ClassInfo): number => { + let maxSeverity = 0; + + for (const slot of first.slots) { + for (const otherSlot of second.slots) { + if (schedulesConflict(slot, otherSlot)) { + maxSeverity = Math.max(maxSeverity, conflictsSeverity(slot, otherSlot)); + } + } + } + + return maxSeverity; +} + const schedulesConflict = (first: SlotInfo, second: SlotInfo) => { if (first.day !== second.day) return false @@ -395,5 +409,6 @@ export { uniqueTeachersFromCourseInfo, teacherIdsFromCourseInfo, scrollToTop, + classesConflictSeverity, plausible }