From e54f488b170d5a9af646c1ac82e8b33579fef61d Mon Sep 17 00:00:00 2001 From: Abhinav Chadaga Date: Sat, 17 Feb 2024 14:30:59 -0600 Subject: [PATCH] feat: implement flatten course schedule helper function takes a course schedule and returns an array of objects that can be used to render all the individual course --- .../components/CalendarCourseCell.stories.tsx | 18 ++-- .../CalendarCourseCell/CalendarCourseCell.tsx | 35 ++++---- src/views/hooks/useFlattenedCourseSchedule.ts | 85 +++++++++++++++++++ 3 files changed, 114 insertions(+), 24 deletions(-) create mode 100644 src/views/hooks/useFlattenedCourseSchedule.ts diff --git a/src/stories/components/CalendarCourseCell.stories.tsx b/src/stories/components/CalendarCourseCell.stories.tsx index 19c1908ef..c1ecdb3c8 100644 --- a/src/stories/components/CalendarCourseCell.stories.tsx +++ b/src/stories/components/CalendarCourseCell.stories.tsx @@ -13,9 +13,12 @@ const meta = { }, tags: ['autodocs'], argTypes: { - course: { control: 'object' }, - meetingIdx: { control: 'number' }, - colors: { control: 'object' }, + department: { control: { type: 'text' } }, + courseNumber: { control: { type: 'text' } }, + instructorLastName: { control: { type: 'text' } }, + status: { control: { type: 'select', options: Object.values(Status) } }, + meetingTime: { control: { type: 'text' } }, + colors: { control: { type: 'object' } }, }, render: (args: any) => (
@@ -23,8 +26,13 @@ const meta = {
), args: { - course: exampleCourse, - meetingIdx: 0, + department: exampleCourse.department, + courseNumber: exampleCourse.number, + instructorLastName: exampleCourse.instructors[0].lastName, + status: exampleCourse.status, + meetingTime: exampleCourse.schedule.meetings[0].getTimeString({separator: '-'}), + + colors: getCourseColors('emerald', 500), }, } satisfies Meta; diff --git a/src/views/components/common/CalendarCourseCell/CalendarCourseCell.tsx b/src/views/components/common/CalendarCourseCell/CalendarCourseCell.tsx index f8e7eb120..3506d6a00 100644 --- a/src/views/components/common/CalendarCourseCell/CalendarCourseCell.tsx +++ b/src/views/components/common/CalendarCourseCell/CalendarCourseCell.tsx @@ -1,5 +1,4 @@ -import { Course, Status } from '@shared/types/Course'; -import { CourseMeeting } from '@shared/types/CourseMeeting'; +import { Status } from '@shared/types/Course'; import React from 'react'; import { CourseColors, pickFontColor } from 'src/shared/util/colors'; import ClosedIcon from '~icons/material-symbols/lock'; @@ -7,7 +6,6 @@ import WaitlistIcon from '~icons/material-symbols/timelapse'; import CancelledIcon from '~icons/material-symbols/warning'; import Text from '../Text/Text'; -export interface CalendarCourseBlockProps { /** The Course that the meeting is for. */ course: Course; /* index into course meeting array to display */ @@ -15,18 +13,18 @@ export interface CalendarCourseBlockProps { colors: CourseColors; } -const CalendarCourseBlock: React.FC = ({ - course, - meetingIdx, +const CalendarCourseCell: React.FC = ({ + courseDeptAndInstr, + timeAndLocation, + status, colors, -}: CalendarCourseBlockProps) => { - let meeting: CourseMeeting | null = meetingIdx !== undefined ? course.schedule.meetings[meetingIdx] : null; +}: CalendarCourseCellProps) => { let rightIcon: React.ReactNode | null = null; - if (course.status === Status.WAITLISTED) { + if (status === Status.WAITLISTED) { rightIcon = ; - } else if (course.status === Status.CLOSED) { + } else if (status === Status.CLOSED) { rightIcon = ; - } else if (course.status === Status.CANCELLED) { + } else if (status === Status.CANCELLED) { rightIcon = ; } @@ -42,14 +40,13 @@ const CalendarCourseBlock: React.FC = ({ >
- {course.department} {course.number} - {course.instructors[0].lastName} - - - {meeting && - `${meeting.getTimeString({ separator: '–', capitalize: true })}${ - meeting.location ? ` – ${meeting.location.building}` : '' - }`} + {courseDeptAndInstr} + {timeAndLocation && ( + + {timeAndLocation} + + )}
{rightIcon && (
= ({ ); }; -export default CalendarCourseBlock; +export default CalendarCourseCell; diff --git a/src/views/hooks/useFlattenedCourseSchedule.ts b/src/views/hooks/useFlattenedCourseSchedule.ts new file mode 100644 index 000000000..0f3243644 --- /dev/null +++ b/src/views/hooks/useFlattenedCourseSchedule.ts @@ -0,0 +1,85 @@ +import { CalendarCourseCellProps } from 'src/views/components/common/CalendarCourseCell/CalendarCourseCell'; +import useSchedules from './useSchedules'; + +const dayToNumber = { + Monday: 0, + Tuesday: 1, + Wednesday: 2, + Thursday: 3, + Friday: 4, +}; + +interface CalendarGridPoint { + dayIndex: number; + startIndex: number; + endIndex: number; +} + +interface SomeObject { + calendarGridPoint?: CalendarGridPoint; + componentProps: CalendarCourseCellProps; +} + +const convertMinutesToIndex = (minutes: number): number => Math.floor(minutes - 420 / 30); + +export function useFlattenedCourseSchedule() { + const [activeSchedule] = useSchedules(); + const { courses } = activeSchedule; + + const out = courses.flatMap(course => { + const { + status, + department, + instructors, + schedule: { meetings }, + } = course; + const courseDeptAndInstr = `${department} ${instructors[0].lastName}`; + + if (meetings.length === 0) { + // asynch, online course + return [ + { + componentProps: { + courseDeptAndInstr, + status, + colors: { + primaryColor: 'ut-gray', + secondaryColor: 'ut-gray', + }, + }, + }, + ]; + } + return meetings.flatMap(meeting => { + const { days, startTime, endTime, location } = meeting; + const time = meeting.getTimeString({ separator: ' - ', capitalize: true }); + const timeAndLocation = `${time} - ${location ? location.building : 'WB'}`; + + return days.map(d => { + const dayIndex = dayToNumber[d]; + const startIndex = convertMinutesToIndex(startTime); + const endIndex = convertMinutesToIndex(endTime); + const calendarGridPoint: CalendarGridPoint = { + dayIndex, + startIndex, + endIndex, + }; + + return { + calendarGridPoint, + componentProps: { + courseDeptAndInstr, + timeAndLocation, + status, + colors: { + primaryColor: 'ut-orange', + secondaryColor: 'ut-orange', + }, + }, + }; + }); + }); + }); + + return out; +}