course conflict highlighting and calculations

This commit is contained in:
Sriram Hariharan
2023-03-22 22:16:51 -05:00
parent 882b5b4e00
commit 2ddfde2642
7 changed files with 54 additions and 8 deletions

View File

@@ -20,4 +20,5 @@ export const userScheduleStore = createLocalStore<IUserScheduleStore>({
], ],
}); });
debugStore({ userScheduleStore }); debugStore({ userScheduleStore });

View File

@@ -1,6 +1,6 @@
/* eslint-disable max-classes-per-file */ /* eslint-disable max-classes-per-file */
import { Serialized } from 'chrome-extension-toolkit'; import { Serialized } from 'chrome-extension-toolkit';
import { capitalize } from '../util/string'; import { CourseMeeting } from './CourseMeeting';
import { CourseSchedule } from './CourseSchedule'; import { CourseSchedule } from './CourseSchedule';
import Instructor from './Instructor'; import Instructor from './Instructor';
@@ -74,6 +74,24 @@ export class Course {
this.schedule = new CourseSchedule(course.schedule); this.schedule = new CourseSchedule(course.schedule);
this.instructors = course.instructors.map(i => new Instructor(i)); this.instructors = course.instructors.map(i => new Instructor(i));
} }
/**
* Gets a list of all the conflicts between this course and another course (i.e. if they have a meeting at the same time)
* @param other another course to compare this course to
* @returns a list of all the conflicts between this course and the other course as a tuple of the two conflicting meetings
*/
getConflicts(other: Course): [CourseMeeting, CourseMeeting][] {
const conflicts: [CourseMeeting, CourseMeeting][] = [];
for (const meeting of this.schedule.meetings) {
for (const otherMeeting of other.schedule.meetings) {
if (meeting.isConflicting(otherMeeting)) {
conflicts.push([meeting, otherMeeting]);
}
}
}
return conflicts;
}
} }
/** /**

View File

@@ -41,6 +41,22 @@ export class CourseMeeting {
Object.assign(this, meeting); Object.assign(this, meeting);
} }
/**
* Whether or not this meeting conflicts with another meeting
* MWF 10:00 am - 11:00 am conflicts with a F 10:00 am - 10:30 am
* @param meeting the meeting to check for conflicts with
* @returns true if the given meeting conflicts with this meeting, false otherwise
*/
isConflicting(meeting: CourseMeeting): boolean {
const { days, startTime, endTime } = this;
const { days: otherDays, startTime: otherStartTime, endTime: otherEndTime } = meeting;
const hasDayConflict = days.some(day => otherDays.includes(day));
const hasTimeConflict = startTime < otherEndTime && endTime > otherStartTime;
return hasDayConflict && hasTimeConflict;
}
/** /**
* Return the string representation of the days of the week that this meeting is taught * Return the string representation of the days of the week that this meeting is taught
* @param options options for the string representation * @param options options for the string representation

View File

@@ -71,7 +71,7 @@ export default function CourseCatalogMain({ support }: Props) {
key={row.course.uniqueId} key={row.course.uniqueId}
row={row} row={row}
isSelected={row.course.uniqueId === selectedCourse?.uniqueId} isSelected={row.course.uniqueId === selectedCourse?.uniqueId}
isInActiveSchedule={Boolean(activeSchedule?.containsCourse(row.course))} activeSchedule={activeSchedule}
onClick={handleRowButtonClick(row.course)} onClick={handleRowButtonClick(row.course)}
/> />
); );

View File

@@ -14,7 +14,6 @@ import {
queryAggregateDistribution, queryAggregateDistribution,
querySemesterDistribution, querySemesterDistribution,
} from 'src/views/lib/database/queryDistribution'; } from 'src/views/lib/database/queryDistribution';
import { bMessenger } from 'src/shared/messages';
import styles from './GradeDistribution.module.scss'; import styles from './GradeDistribution.module.scss';
enum DataStatus { enum DataStatus {
@@ -137,7 +136,6 @@ export default function GradeDistribution({ course }: Props) {
useEffect(() => { useEffect(() => {
queryAggregateDistribution(course) queryAggregateDistribution(course)
.then(([distribution, semesters]) => { .then(([distribution, semesters]) => {
console.log('.then -> distribution, semesters:', distribution, semesters);
setSemesters(semesters); setSemesters(semesters);
updateChart(distribution); updateChart(distribution);
setStatus(DataStatus.FOUND); setStatus(DataStatus.FOUND);

View File

@@ -21,7 +21,8 @@
.isConflict { .isConflict {
* { * {
color: $speedway_brick !important; color: $speedway_brick;
text-decoration: line-through !important; text-decoration: line-through !important;
font-weight: normal !important;
} }
} }

View File

@@ -50,9 +50,21 @@ export default function TableRow({ row, isSelected, activeSchedule, onClick }: P
}, [activeSchedule, element.classList]); }, [activeSchedule, element.classList]);
useEffect(() => { useEffect(() => {
// if (!activeSchedule || !course) return; if (!activeSchedule || !course) {
// TODO: handle conflicts here return;
}, []); }
let hasConflicts = activeSchedule.courses.find(c => {
let conflicts = course.getConflicts(c);
return conflicts.length > 0;
});
element.classList[hasConflicts ? 'add' : 'remove'](styles.isConflict);
return () => {
element.classList.remove(styles.isConflict);
};
}, [activeSchedule, course]);
if (!container) { if (!container) {
return null; return null;