Skip to content

Commit

Permalink
fix: Color Changing Bug w/ Duplicate Courses (#719)
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinWu098 authored Oct 27, 2023
1 parent b655b97 commit 3ac6df7
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 110 deletions.
1 change: 0 additions & 1 deletion apps/antalmanac/src/components/Calendar/CalendarRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,6 @@ class ScheduleCalendar extends PureComponent<ScheduleCalendarProps, ScheduleCale
return (
<div className={classes.container} style={isMobile ? { height: 'calc(100% - 50px)' } : undefined}>
<CalendarToolbar
onTakeScreenshot={this.handleTakeScreenshot}
currentScheduleIndex={this.state.currentScheduleIndex}
toggleDisplayFinalsSchedule={this.toggleDisplayFinalsSchedule}
showFinalsSchedule={this.state.showFinalsSchedule}
Expand Down
190 changes: 84 additions & 106 deletions apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { IconButton } from '@material-ui/core';
import CloseIcon from '@material-ui/icons/Close';
import React, { useCallback, useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import LazyLoad from 'react-lazyload';

import { Alert } from '@mui/material';
import { Alert, Box, IconButton } from '@mui/material';
import { Close } from '@mui/icons-material';
import { AACourse, AASection } from '@packages/antalmanac-types';
import { WebsocDepartment, WebsocSchool, WebsocAPIResponse, GE } from 'peterportal-api-next-types';
import RightPaneStore from '../RightPaneStore';
Expand All @@ -20,11 +19,18 @@ import Grades from '$lib/grades';
import analyticsEnum from '$lib/analytics';
import { openSnackbar } from '$actions/AppStoreActions';

function flattenSOCObject(SOCObject: WebsocAPIResponse): (WebsocSchool | WebsocDepartment | AACourse)[] {
const courseColors = AppStore.getAddedCourses().reduce((accumulator, { section }) => {
function getColors() {
const courseColors = AppStore.schedule.getCurrentCourses().reduce((accumulator, { section }) => {
accumulator[section.sectionCode] = section.color;
return accumulator;
}, {} as { [key: string]: string });

return courseColors;
}

const flattenSOCObject = (SOCObject: WebsocAPIResponse): (WebsocSchool | WebsocDepartment | AACourse)[] => {
const courseColors = getColors();

return SOCObject.schools.reduce((accumulator: (WebsocSchool | WebsocDepartment | AACourse)[], school) => {
accumulator.push(school);

Expand All @@ -43,7 +49,7 @@ function flattenSOCObject(SOCObject: WebsocAPIResponse): (WebsocSchool | WebsocD
}, []);
}
const RecruitmentBanner = () => {
const [bannerVisibility, setBannerVisibility] = React.useState<boolean>(true);
const [bannerVisibility, setBannerVisibility] = useState(true);

// Display recruitment banner if more than 11 weeks (in ms) has passed since last dismissal
const recruitmentDismissalTime = window.localStorage.getItem('recruitmentDismissalTime');
Expand All @@ -54,7 +60,7 @@ const RecruitmentBanner = () => {
const displayRecruitmentBanner = bannerVisibility && !dismissedRecently && isSearchCS;

return (
<div style={{ position: 'fixed', bottom: 5, right: 5, zIndex: 999 }}>
<Box sx={{ position: 'fixed', bottom: 5, right: 5, zIndex: 999 }}>
{displayRecruitmentBanner ? (
<Alert
icon={false}
Expand All @@ -73,7 +79,7 @@ const RecruitmentBanner = () => {
setBannerVisibility(false);
}}
>
<CloseIcon fontSize="inherit" />
<Close fontSize="inherit" />
</IconButton>
}
>
Expand All @@ -85,8 +91,8 @@ const RecruitmentBanner = () => {
<br />
We have opportunities for experienced devs and those with zero experience!
</Alert>
) : null}{' '}
</div>
) : null}
</Box>
);
};

Expand Down Expand Up @@ -136,33 +142,38 @@ const SectionTableWrapped = (
return <div>{component}</div>;
};

export function CourseRenderPane() {
const LoadingMessage = () => {
return (
<Box sx={{ height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<img src={isDarkMode() ? darkModeLoadingGif : loadingGif} alt="Loading courses" />
</Box>
);
};

const ErrorMessage = () => {
return (
<Box sx={{ height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<img
src={isDarkMode() ? darkNoNothing : noNothing}
alt="No Results Found"
style={{ objectFit: 'contain', width: '80%', height: '80%' }}
/>
</Box>
);
};

export default function CourseRenderPane() {
const [websocResp, setWebsocResp] = useState<WebsocAPIResponse>();
const [courseData, setCourseData] = useState<(WebsocSchool | WebsocDepartment | AACourse)[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
const [scheduleNames, setScheduleNames] = useState(AppStore.getScheduleNames());
const [courseData, setCourseData] = useState<(WebsocSchool | WebsocDepartment | AACourse)[]>([]);

const loadCourses = useCallback(async () => {
setLoading(true);

const formData = RightPaneStore.getFormData();

const params = {
department: formData.deptValue,
term: formData.term,
ge: formData.ge,
courseNumber: formData.courseNumber,
sectionCodes: formData.sectionCode,
instructorName: formData.instructor,
units: formData.units,
endTime: formData.endTime,
startTime: formData.startTime,
fullCourses: formData.coursesFull,
building: formData.building,
room: formData.room,
division: formData.division,
};

const websocQueryParams = {
department: formData.deptValue,
term: formData.term,
Expand Down Expand Up @@ -194,6 +205,7 @@ export function CourseRenderPane() {
]);

setError(false);
setWebsocResp(websocJsonResp);
setCourseData(flattenSOCObject(websocJsonResp));
} catch (error) {
console.error(error);
Expand All @@ -204,95 +216,61 @@ export function CourseRenderPane() {
}
}, []);

useEffect(() => {
loadCourses();
}, []);
const updateScheduleNames = () => {
setScheduleNames(AppStore.getScheduleNames());
};

useEffect(() => {
const updateScheduleNames = () => {
setScheduleNames(AppStore.getScheduleNames());
const changeColors = () => {
if (websocResp == null) {
return;
}
setCourseData(flattenSOCObject(websocResp));
};

AppStore.on('scheduleNamesChange', updateScheduleNames);
AppStore.on('currentScheduleIndexChange', changeColors);

return () => {
AppStore.off('scheduleNamesChange', updateScheduleNames);
AppStore.off('currentScheduleIndexChange', changeColors);
};
}, []);
}, [websocResp]);

if (loading) {
return (
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<img src={isDarkMode() ? darkModeLoadingGif : loadingGif} alt="Loading courses" />
</div>
);
}
useEffect(() => {
loadCourses();
AppStore.on('scheduleNamesChange', updateScheduleNames);

if (error) {
return (
<div
style={{
height: '100%',
overflowY: 'scroll',
position: 'relative',
}}
>
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<img src={isDarkMode() ? darkNoNothing : noNothing} alt="No Results Found" />
</div>
</div>
);
}
return () => {
AppStore.off('scheduleNamesChange', updateScheduleNames);
};
}, [loadCourses]);

return (
<>
<RecruitmentBanner />
<div style={{ height: '100%', overflowY: 'scroll', position: 'relative' }}>
<div style={{ height: '50px', marginBottom: '5px' }} />
{courseData.length === 0 ? (
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<img src={isDarkMode() ? darkNoNothing : noNothing} alt="No Results Found" />
</div>
) : (
courseData.map((_, index: number) => {
let heightEstimate = 200;
if ((courseData[index] as AACourse).sections !== undefined)
heightEstimate = (courseData[index] as AACourse).sections.length * 60 + 20 + 40;

return (
<LazyLoad once key={index} overflow height={heightEstimate} offset={500}>
{SectionTableWrapped(index, { courseData, scheduleNames })}
</LazyLoad>
);
})
)}
</div>
{loading ? (
<LoadingMessage />
) : error || courseData.length === 0 ? (
<ErrorMessage />
) : (
<>
<RecruitmentBanner />
<Box>
<Box sx={{ height: '50px', marginBottom: '5px' }} />
{courseData.map((_: WebsocSchool | WebsocDepartment | AACourse, index: number) => {
let heightEstimate = 200;
if ((courseData[index] as AACourse).sections !== undefined)
heightEstimate = (courseData[index] as AACourse).sections.length * 60 + 20 + 40;
return (
<LazyLoad once key={index} overflow height={heightEstimate} offset={500}>
{SectionTableWrapped(index, {
courseData: courseData,
scheduleNames: scheduleNames,
})}
</LazyLoad>
);
})}
</Box>
</>
)}
</>
);
}

export default CourseRenderPane;
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const ColorAndDelete = withStyles(styles)((props: ColorAndDeleteProps) =>
<Delete fontSize="small" />
</IconButton>
<ColorPicker
key={AppStore.getCurrentScheduleIndex()}
color={color}
isCustomEvent={false}
sectionCode={sectionCode}
Expand Down
19 changes: 16 additions & 3 deletions apps/antalmanac/src/stores/Schedules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export class Schedules {
}

/**
* @return Reference of the course that matches the params
* @return A course that matches the params across all schedules
*/
getExistingCourse(sectionCode: string, term: string) {
for (const course of this.getAllCourses()) {
Expand All @@ -159,6 +159,18 @@ export class Schedules {
return undefined;
}

/**
* @return A course that matches the params in the current schedule
*/
getExistingCourseInSchedule(sectionCode: string, term: string) {
for (const course of this.getCurrentCourses()) {
if (course.section.sectionCode === sectionCode && term === course.term) {
return course;
}
}
return undefined;
}

/**
* Adds a course to a given schedule index
* Sets color to an unused color in set, also will not add class if already exists
Expand All @@ -172,7 +184,7 @@ export class Schedules {
this.addUndoState();
}

const existingSection = this.getExistingCourse(newCourse.section.sectionCode, newCourse.term);
const existingSection = this.getExistingCourseInSchedule(newCourse.section.sectionCode, newCourse.term);

const existsInSchedule = this.doesCourseExistInSchedule(
newCourse.section.sectionCode,
Expand Down Expand Up @@ -222,7 +234,8 @@ export class Schedules {
*/
changeCourseColor(sectionCode: string, term: string, newColor: string) {
this.addUndoState();
const course = this.getExistingCourse(sectionCode, term);

const course = this.getExistingCourseInSchedule(sectionCode, term);
if (course) {
course.section.color = newColor;
}
Expand Down

0 comments on commit 3ac6df7

Please sign in to comment.