From a851befa05d79c1b0aad99aeecae3a0b05b35b0b Mon Sep 17 00:00:00 2001 From: Dalton Adcock Date: Wed, 13 Mar 2024 05:44:41 -0700 Subject: [PATCH] Extending the Hover Feature for Finals (#919) --- .../src/components/Calendar/CalendarRoot.tsx | 23 ++++--- .../RightPane/CoursePane/CourseRenderPane.tsx | 6 +- .../SectionTable/SectionTableBody.tsx | 23 +++---- apps/antalmanac/src/lib/termData.ts | 4 +- apps/antalmanac/src/stores/HoveredStore.ts | 68 +++++++++++++------ 5 files changed, 80 insertions(+), 44 deletions(-) diff --git a/apps/antalmanac/src/components/Calendar/CalendarRoot.tsx b/apps/antalmanac/src/components/Calendar/CalendarRoot.tsx index b1dccb664..e7379d420 100644 --- a/apps/antalmanac/src/components/Calendar/CalendarRoot.tsx +++ b/apps/antalmanac/src/components/Calendar/CalendarRoot.tsx @@ -80,14 +80,18 @@ export default function ScheduleCalendar(props: ScheduleCalendarProps) { const [scheduleNames, setScheduleNames] = useState(AppStore.getScheduleNames()); const { isMilitaryTime } = useTimeFormatStore(); - const { hoveredCourseEvents } = useHoveredStore(); + const [hoveredCalendarizedCourses, hoveredCalendarizedFinal] = useHoveredStore((store) => [ + store.hoveredCalendarizedCourses, + store.hoveredCalendarizedFinal, + ]); const getEventsForCalendar = (): CalendarEvent[] => { - return showFinalsSchedule - ? finalsEventsInCalendar - : hoveredCourseEvents - ? [...eventsInCalendar, ...hoveredCourseEvents] - : eventsInCalendar; + if (showFinalsSchedule) + return hoveredCalendarizedFinal + ? [...finalsEventsInCalendar, hoveredCalendarizedFinal] + : finalsEventsInCalendar; + else + return hoveredCalendarizedCourses ? [...eventsInCalendar, ...hoveredCalendarizedCourses] : eventsInCalendar; }; const handleClosePopover = () => { @@ -165,8 +169,11 @@ export default function ScheduleCalendar(props: ScheduleCalendarProps) { const onlyCourseEvents = eventsInCalendar.filter((e) => !e.isCustomEvent) as CourseEvent[]; - const finalsDate = - onlyCourseEvents.length > 0 ? getFinalsStartDateForTerm(onlyCourseEvents[0].term) : getDefaultFinalsStartDate(); + const finalsDate = hoveredCalendarizedFinal + ? getFinalsStartDateForTerm(hoveredCalendarizedFinal.term) + : onlyCourseEvents.length > 0 + ? getFinalsStartDateForTerm(onlyCourseEvents[0].term) + : getDefaultFinalsStartDate(); const finalsDateFormat = finalsDate ? 'ddd MM/DD' : 'ddd'; const date = showFinalsSchedule && finalsDate ? finalsDate : new Date(2018, 0, 1); diff --git a/apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane.tsx b/apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane.tsx index 70f99aec1..bd99c5fbe 100644 --- a/apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane.tsx +++ b/apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane.tsx @@ -182,7 +182,7 @@ export default function CourseRenderPane(props: { id?: number }) { const [error, setError] = useState(false); const [scheduleNames, setScheduleNames] = useState(AppStore.getScheduleNames()); - const setHoveredCourseEvents = useHoveredStore((store) => store.setHoveredCourseEvents); + const setHoveredEvents = useHoveredStore((store) => store.setHoveredEvents); const loadCourses = useCallback(async () => { setLoading(true); @@ -270,9 +270,9 @@ export default function CourseRenderPane(props: { id?: number }) { */ useEffect(() => { return () => { - setHoveredCourseEvents(undefined); + setHoveredEvents(undefined); }; - }, [setHoveredCourseEvents]); + }, []); return ( <> diff --git a/apps/antalmanac/src/components/RightPane/SectionTable/SectionTableBody.tsx b/apps/antalmanac/src/components/RightPane/SectionTable/SectionTableBody.tsx index e9db39961..50f27d23e 100644 --- a/apps/antalmanac/src/components/RightPane/SectionTable/SectionTableBody.tsx +++ b/apps/antalmanac/src/components/RightPane/SectionTable/SectionTableBody.tsx @@ -531,20 +531,19 @@ const SectionTableBody = withStyles(styles)((props: SectionTableBodyProps) => { setCalendarEvents(AppStore.getCourseEventsInCalendar()); }, [setCalendarEvents]); - const [hoveredCourseEvents, setHoveredCourseEvents] = useHoveredStore((store) => [ - store.hoveredCourseEvents, - store.setHoveredCourseEvents, - ]); + const [hoveredEvents, setHoveredEvents] = useHoveredStore((store) => [store.hoveredEvents, store.setHoveredEvents]); + + const alreadyHovered = useMemo(() => { + return hoveredEvents?.some((scheduleCourse) => scheduleCourse.section.sectionCode == section.sectionCode); + }, [hoveredEvents, section.sectionCode]); const handleHover = useCallback(() => { - const alreadyHovered = - hoveredCourseEvents && - hoveredCourseEvents.some((courseEvent) => courseEvent.sectionCode == section.sectionCode); - - !previewMode || alreadyHovered || addedCourse - ? setHoveredCourseEvents(undefined) - : setHoveredCourseEvents(section, courseDetails, term); - }, [addedCourse, courseDetails, hoveredCourseEvents, previewMode, section, setHoveredCourseEvents, term]); + if (!previewMode || alreadyHovered || addedCourse) { + setHoveredEvents(undefined); + } else { + setHoveredEvents(section, courseDetails, term); + } + }, [alreadyHovered, section, courseDetails, term]); // Attach event listeners to the store. useEffect(() => { diff --git a/apps/antalmanac/src/lib/termData.ts b/apps/antalmanac/src/lib/termData.ts index 8e9cd0733..d63e062e7 100644 --- a/apps/antalmanac/src/lib/termData.ts +++ b/apps/antalmanac/src/lib/termData.ts @@ -112,13 +112,13 @@ function getFinalsStartForTerm(term: string) { */ function getDefaultFinalsStartDate() { // FIXME: Un-offset once Spring starts, or figure out a proper fix - const [year, month, day] = termData[defaultTerm + 1].finalsStartDate || []; + const [year, month, day] = getDefaultFinalsStart() ?? []; return year && month && day ? new Date(year, month, day + 1) : undefined; } function getFinalsStartDateForTerm(term: string) { const date = getFinalsStartForTerm(term); - const [year, month, day] = date || []; + const [year, month, day] = date ?? []; return year && month && day ? new Date(year, month, day + 1) : undefined; } diff --git a/apps/antalmanac/src/stores/HoveredStore.ts b/apps/antalmanac/src/stores/HoveredStore.ts index 5245399ef..5132a79ab 100644 --- a/apps/antalmanac/src/stores/HoveredStore.ts +++ b/apps/antalmanac/src/stores/HoveredStore.ts @@ -1,32 +1,62 @@ import { create } from 'zustand'; -import { AASection } from '@packages/antalmanac-types'; -import { calendarizeCourseEvents } from './calendarizeHelpers'; +import { AASection, ScheduleCourse } from '@packages/antalmanac-types'; +import { calendarizeCourseEvents, calendarizeFinals } from './calendarizeHelpers'; import { CourseEvent } from '$components/Calendar/CourseCalendarEvent'; import { CourseDetails } from '$lib/course_data.types'; +const HOVERED_SECTION_COLOR = '#80808080'; export interface HoveredStore { - hoveredCourseEvents: CourseEvent[] | undefined; - setHoveredCourseEvents: (section?: AASection, courseDetails?: CourseDetails, term?: string) => void; + hoveredEvents: ScheduleCourse[] | undefined; + setHoveredEvents: (section?: AASection, courseDetails?: CourseDetails, term?: string) => void; + hoveredCalendarizedCourses: CourseEvent[] | undefined; + hoveredCalendarizedFinal: CourseEvent | undefined; } +const DEFAULT_HOVERED_STORE = { + hoveredEvents: undefined, + hoveredCalendarizedCourses: undefined, + hoveredCalendarizedFinal: undefined, +}; + export const useHoveredStore = create((set) => { return { - hoveredCourseEvents: undefined, - setHoveredCourseEvents: (section, courseDetails, term) => { + ...DEFAULT_HOVERED_STORE, + setHoveredEvents: (section, courseDetails, term) => { + if (section == null || courseDetails == null || term == null) { + set({ ...DEFAULT_HOVERED_STORE }); + return; + } set({ - hoveredCourseEvents: - section && courseDetails && term - ? calendarizeCourseEvents([ - { - ...courseDetails, - section: { - ...section, - color: '#80808080', - }, - term, - }, - ]) - : undefined, + hoveredEvents: [ + { + ...courseDetails, + section: { + ...section, + color: HOVERED_SECTION_COLOR, + }, + term, + }, + ], + hoveredCalendarizedCourses: calendarizeCourseEvents([ + { + ...courseDetails, + section: { + ...section, + color: HOVERED_SECTION_COLOR, + }, + term, + }, + ]), + hoveredCalendarizedFinal: calendarizeFinals([ + { + ...courseDetails, + section: { + ...section, + color: HOVERED_SECTION_COLOR, + }, + term, + }, + ])[0], }); }, };