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:
@@ -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>;
|
||||||
|
|||||||
@@ -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>
|
||||||
|
{timeAndLocation && (
|
||||||
<Text variant='h3-course' className='leading-[75%]!'>
|
<Text variant='h3-course' className='leading-[75%]!'>
|
||||||
{meeting &&
|
{timeAndLocation}
|
||||||
`${meeting.getTimeString({ separator: '–', capitalize: true })}${
|
|
||||||
meeting.location ? ` – ${meeting.location.building}` : ''
|
|
||||||
}`}
|
|
||||||
</Text>
|
</Text>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{rightIcon && (
|
{rightIcon && (
|
||||||
<div
|
<div
|
||||||
@@ -65,4 +62,4 @@ const CalendarCourseBlock: React.FC<CalendarCourseBlockProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CalendarCourseBlock;
|
export default CalendarCourseCell;
|
||||||
|
|||||||
85
src/views/hooks/useFlattenedCourseSchedule.ts
Normal file
85
src/views/hooks/useFlattenedCourseSchedule.ts
Normal 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user