diff --git a/src/stories/components/CalendarCourse.stories.tsx b/src/stories/components/CalendarCourse.stories.tsx new file mode 100644 index 00000000..6fd53f59 --- /dev/null +++ b/src/stories/components/CalendarCourse.stories.tsx @@ -0,0 +1,62 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { Course, Status } from 'src/shared/types/Course'; +import { CourseMeeting, DAY_MAP } from 'src/shared/types/CourseMeeting'; +import { CourseSchedule } from 'src/shared/types/CourseSchedule'; +import Instructor from 'src/shared/types/Instructor'; +import CalendarCourse from 'src/views/components/common/CalendarCourseMeeting/CalendarCourseMeeting'; + +const meta = { + title: 'Components/Common/CalendarCourseMeeting', + component: CalendarCourse, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + course: { control: 'object' }, + meetingIdx: { control: 'number' }, + color: { control: 'color' }, + rightIcon: { control: 'object' }, + }, +} satisfies Meta; +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + course: new Course({ + uniqueId: 123, + number: '101', + fullName: 'Course 101', + courseName: 'Course', + department: 'BVO', + creditHours: 3, + status: Status.OPEN, + instructors: [new Instructor({ firstName: '', lastName: 'Bevo', fullName: 'Bevo' })], + isReserved: false, + url: '', + flags: [], + schedule: new CourseSchedule({ + meetings: [ + new CourseMeeting({ + days: [DAY_MAP.M, DAY_MAP.W, DAY_MAP.F], + startTime: 480, + endTime: 570, + location: { + building: 'UTC', + room: '123', + }, + }), + ], + }), + instructionMode: 'In Person', + semester: { + year: 2024, + season: 'Spring', + }, + }), + meetingIdx: 0, + color: 'red', + }, +}; diff --git a/src/views/components/common/CalendarCourseMeeting/CalendarCourseMeeting.module.scss b/src/views/components/common/CalendarCourseMeeting/CalendarCourseMeeting.module.scss new file mode 100644 index 00000000..f41b942b --- /dev/null +++ b/src/views/components/common/CalendarCourseMeeting/CalendarCourseMeeting.module.scss @@ -0,0 +1,11 @@ +.calendar-course { + display: flex; + padding: 7px 7px 9px 7px; + flex-direction: column; + align-items: flex-start; + gap: 5px; + flex: 1 0 0; + align-self: stretch; + border-radius: 4px; + background: #cbd5e1; +} diff --git a/src/views/components/common/CalendarCourseMeeting/CalendarCourseMeeting.tsx b/src/views/components/common/CalendarCourseMeeting/CalendarCourseMeeting.tsx new file mode 100644 index 00000000..cabf2154 --- /dev/null +++ b/src/views/components/common/CalendarCourseMeeting/CalendarCourseMeeting.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { Course } from 'src/shared/types/Course'; +import { CourseMeeting } from 'src/shared/types/CourseMeeting'; +import styles from './CalendarCourseMeeting.module.scss'; + +/** + * Props for the CalendarCourseMeeting component. + */ +export interface CalendarCourseMeetingProps { + /** The Course that the meeting is for. */ + course: Course; + /* index into course meeting array to display */ + meetingIdx?: number; + /** The background color for the course. */ + color: string; + /** The icon to display on the right side of the course. This is optional. */ + rightIcon?: React.ReactNode; +} + +/** + * `CalendarCourseMeeting` is a functional component that displays a course meeting. + * + * @example + * } /> + */ +const CalendarCourseMeeting: React.FC = ({ + course, + meetingIdx, +}: CalendarCourseMeetingProps) => { + let meeting: CourseMeeting | null = meetingIdx !== undefined ? course.schedule.meetings[meetingIdx] : null; + return ( +
+
+ {course.department} {course.number} - {course.instructors[0].lastName} +
+ {meeting && ( +
+ {`${meeting.getTimeString({ separator: '-', capitalize: true })}${ + meeting.location ? ` - ${meeting.location.building}` : '' + }`} +
+ )} +
+ ); +}; + +export default CalendarCourseMeeting;