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
This commit is contained in:
Abhinav Chadaga
2024-02-17 14:30:59 -06:00
parent 2f19c57553
commit bba067f591
3 changed files with 114 additions and 24 deletions

View File

@@ -13,9 +13,12 @@ const meta = {
}, },
tags: ['autodocs'], tags: ['autodocs'],
argTypes: { argTypes: {
course: { control: 'object' }, department: { control: { type: 'text' } },
meetingIdx: { control: 'number' }, courseNumber: { control: { type: 'text' } },
colors: { control: 'object' }, instructorLastName: { control: { type: 'text' } },
status: { control: { type: 'select', options: Object.values(Status) } },
meetingTime: { control: { type: 'text' } },
colors: { control: { type: 'object' } },
}, },
render: (args: any) => ( render: (args: any) => (
<div className='w-45'> <div className='w-45'>
@@ -23,8 +26,13 @@ const meta = {
</div> </div>
), ),
args: { args: {
course: exampleCourse, department: exampleCourse.department,
meetingIdx: 0, courseNumber: exampleCourse.number,
instructorLastName: exampleCourse.instructors[0].lastName,
status: exampleCourse.status,
meetingTime: exampleCourse.schedule.meetings[0].getTimeString({separator: '-'}),
colors: getCourseColors('emerald', 500), colors: getCourseColors('emerald', 500),
}, },
} satisfies Meta<typeof CalendarCourseCell>; } satisfies Meta<typeof CalendarCourseCell>;

View File

@@ -1,5 +1,4 @@
import { Course, Status } from '@shared/types/Course'; import { Status } from '@shared/types/Course';
import { CourseMeeting } from '@shared/types/CourseMeeting';
import React from 'react'; import React from 'react';
import { CourseColors, pickFontColor } from 'src/shared/util/colors'; import { CourseColors, pickFontColor } from 'src/shared/util/colors';
import ClosedIcon from '~icons/material-symbols/lock'; 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 CancelledIcon from '~icons/material-symbols/warning';
import Text from '../Text/Text'; import Text from '../Text/Text';
export interface CalendarCourseBlockProps {
/** The Course that the meeting is for. */ /** The Course that the meeting is for. */
course: Course; course: Course;
/* index into course meeting array to display */ /* index into course meeting array to display */
@@ -15,18 +13,18 @@ export interface CalendarCourseBlockProps {
colors: CourseColors; colors: CourseColors;
} }
const CalendarCourseBlock: React.FC<CalendarCourseBlockProps> = ({ const CalendarCourseCell: React.FC<CalendarCourseCellProps> = ({
course, courseDeptAndInstr,
meetingIdx, timeAndLocation,
status,
colors, colors,
}: CalendarCourseBlockProps) => { }: CalendarCourseCellProps) => {
let meeting: CourseMeeting | null = meetingIdx !== undefined ? course.schedule.meetings[meetingIdx] : null;
let rightIcon: React.ReactNode | null = null; let rightIcon: React.ReactNode | null = null;
if (course.status === Status.WAITLISTED) { if (status === Status.WAITLISTED) {
rightIcon = <WaitlistIcon className='h-5 w-5' />; rightIcon = <WaitlistIcon className='h-5 w-5' />;
} else if (course.status === Status.CLOSED) { } else if (status === Status.CLOSED) {
rightIcon = <ClosedIcon className='h-5 w-5' />; rightIcon = <ClosedIcon className='h-5 w-5' />;
} else if (course.status === Status.CANCELLED) { } else if (status === Status.CANCELLED) {
rightIcon = <CancelledIcon className='h-5 w-5' />; rightIcon = <CancelledIcon className='h-5 w-5' />;
} }
@@ -42,14 +40,13 @@ const CalendarCourseBlock: React.FC<CalendarCourseBlockProps> = ({
> >
<div className='flex flex-1 flex-col gap-1'> <div className='flex flex-1 flex-col gap-1'>
<Text variant='h1-course' className='leading-[75%]!'> <Text variant='h1-course' className='leading-[75%]!'>
{course.department} {course.number} - {course.instructors[0].lastName} {courseDeptAndInstr}
</Text>
<Text variant='h3-course' className='leading-[75%]!'>
{meeting &&
`${meeting.getTimeString({ separator: '', capitalize: true })}${
meeting.location ? ` ${meeting.location.building}` : ''
}`}
</Text> </Text>
{timeAndLocation && (
<Text variant='h3-course' className='leading-[75%]!'>
{timeAndLocation}
</Text>
)}
</div> </div>
{rightIcon && ( {rightIcon && (
<div <div
@@ -65,4 +62,4 @@ const CalendarCourseBlock: React.FC<CalendarCourseBlockProps> = ({
); );
}; };
export default CalendarCourseBlock; export default CalendarCourseCell;

View File

@@ -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;
}