Skip to content

Commit

Permalink
Merge pull request #330 from NIAEFEUP/fix/conflict-triangle-not-showi…
Browse files Browse the repository at this point in the history
…ng-correct-severity

fix: class item conflict indicator correct severity
  • Loading branch information
tomaspalma authored Nov 4, 2024
2 parents 4a7ec54 + 5c26622 commit 3ca1d9f
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 33 deletions.
41 changes: 19 additions & 22 deletions src/components/planner/sidebar/CoursesController/ClassItem.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
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'


type Props = {
course_id: number,
classInfo: ClassInfo
conflict?: boolean
onSelect?: () => void
onMouseEnter?: () => void
onMouseLeave?: () => void
Expand All @@ -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 (
<DropdownMenuCheckboxItem
Expand All @@ -62,8 +61,6 @@ const ClassItem = ({ course_id, classInfo, onSelect, onMouseEnter, onMouseLeave
{classInfo.slots.map((slot, idx) => (
<div key={`${classInfo.name}-${idx}`} className="flex items-center space-x-2">
<span className="text-xs text-gray-500">{slot.lesson_type}</span>
{/* <span className="text-xs text-gray-500">{convertWeekday(slot.day)}</span> */}
{/* <span className="text-xs text-gray-500">{getLessonBoxTime(slot)}</span> */}
<span className="text-xs text-gray-500">{slot.location}</span>
<span className="text-xs text-gray-500">
{slot.professors.map((professor) => professor.acronym).join(', ')}
Expand All @@ -72,7 +69,7 @@ const ClassItem = ({ course_id, classInfo, onSelect, onMouseEnter, onMouseLeave
))}
</div>
</div>
<ExclamationTriangleIcon className={`h-5 w-5 ${conflict ? 'block' : 'hidden'} ${conflict == 2 ? 'text-red-600' : 'text-amber-500'}`} aria-hidden="true" />
<ExclamationTriangleIcon className={`h-5 w-5 ${conflictSeverity() > 0 ? 'block' : 'hidden'} ${conflictSeverity() == 2 ? 'text-red-600' : 'text-amber-500'}`} aria-hidden="true" />
</DropdownMenuCheckboxItem>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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 <>
<div>
{course.classes === null ? (
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
17 changes: 16 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -395,5 +409,6 @@ export {
uniqueTeachersFromCourseInfo,
teacherIdsFromCourseInfo,
scrollToTop,
classesConflictSeverity,
plausible
}

0 comments on commit 3ca1d9f

Please sign in to comment.