feat: show async courses in the bottom bar (#204)
* feat: show async courses in the bottom bar * fix: hide "Async/Other" header when there are no async courses, off-by-n error (where n is the number async courses) * refactor: move types closer to map instead of weird "as boolean" * refactor: move satisfies to return type
This commit is contained in:
@@ -87,7 +87,7 @@ export default function Calendar(): JSX.Element {
|
||||
<div className='min-h-2xl flex-grow overflow-auto pl-2 pr-4 pt-6 screenshot:min-h-xl'>
|
||||
<CalendarGrid courseCells={courseCells} setCourse={setCourse} />
|
||||
</div>
|
||||
<CalendarBottomBar />
|
||||
<CalendarBottomBar courseCells={courseCells} setCourse={setCourse} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import type { Course } from '@shared/types/Course';
|
||||
import { saveAsCal, saveCalAsPng } from '@views/components/calendar/utils';
|
||||
import { Button } from '@views/components/common/Button';
|
||||
import Divider from '@views/components/common/Divider';
|
||||
import Text from '@views/components/common/Text/Text';
|
||||
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
import CalendarMonthIcon from '~icons/material-symbols/calendar-month';
|
||||
import ImageIcon from '~icons/material-symbols/image';
|
||||
|
||||
import type { CalendarCourseCellProps } from './CalendarCourseCell';
|
||||
import CalendarCourseBlock from './CalendarCourseCell';
|
||||
|
||||
type CalendarBottomBarProps = {
|
||||
courses?: CalendarCourseCellProps[];
|
||||
courseCells?: CalendarGridCourse[];
|
||||
setCourse: React.Dispatch<React.SetStateAction<Course | null>>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -21,8 +23,9 @@ type CalendarBottomBarProps = {
|
||||
* @param {Object[]} courses - The list of courses to display in the calendar.
|
||||
* @returns {JSX.Element} The rendered bottom bar component.
|
||||
*/
|
||||
export default function CalendarBottomBar({ courses }: CalendarBottomBarProps): JSX.Element {
|
||||
const displayCourses = courses && courses.length > 0;
|
||||
export default function CalendarBottomBar({ courseCells, setCourse }: CalendarBottomBarProps): JSX.Element {
|
||||
const asyncCourseCells = courseCells?.filter(block => block.async);
|
||||
const displayCourses = asyncCourseCells && asyncCourseCells.length > 0;
|
||||
|
||||
return (
|
||||
<div className='w-full flex py-1.25 pl-7.5 pr-6.25'>
|
||||
@@ -35,15 +38,19 @@ export default function CalendarBottomBar({ courses }: CalendarBottomBarProps):
|
||||
<>
|
||||
<Text variant='h4'>Async/Other:</Text>
|
||||
<div className='inline-flex gap-2.5'>
|
||||
{courses.map(({ courseDeptAndInstr, status, colors, className }) => (
|
||||
<CalendarCourseBlock
|
||||
courseDeptAndInstr={courseDeptAndInstr}
|
||||
status={status}
|
||||
colors={colors}
|
||||
key={courseDeptAndInstr}
|
||||
className={clsx(className, 'w-35! h-15!')}
|
||||
/>
|
||||
))}
|
||||
{asyncCourseCells.map(block => {
|
||||
const { courseDeptAndInstr, status, colors, className } = block.componentProps;
|
||||
return (
|
||||
<CalendarCourseBlock
|
||||
courseDeptAndInstr={courseDeptAndInstr}
|
||||
status={status}
|
||||
colors={colors}
|
||||
key={courseDeptAndInstr}
|
||||
className={clsx(className, 'w-35! h-15!')}
|
||||
onClick={() => setCourse(block.course)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -123,28 +123,30 @@ function AccountForCourseConflicts({ courseCells, setCourse }: AccountForCourseC
|
||||
});
|
||||
});
|
||||
|
||||
return courseCells.map((block, i) => {
|
||||
const { courseDeptAndInstr, timeAndLocation, status } = courseCells[i]!.componentProps;
|
||||
return courseCells
|
||||
.filter(block => !block.async)
|
||||
.map(block => {
|
||||
const { courseDeptAndInstr, timeAndLocation, status } = block.componentProps;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={`${JSON.stringify(block)}`}
|
||||
style={{
|
||||
gridColumn: `${block.calendarGridPoint.dayIndex + 3}`,
|
||||
gridRow: `${block.calendarGridPoint.startIndex} / ${block.calendarGridPoint.endIndex}`,
|
||||
width: `calc(100% / ${block.totalColumns ?? 1})`,
|
||||
marginLeft: `calc(100% * ${((block.gridColumnStart ?? 0) - 1) / (block.totalColumns ?? 1)})`,
|
||||
}}
|
||||
className='pb-1 pl-0 pr-2.5 pt-0 screenshot:pb-0.5 screenshot:pr-0.5'
|
||||
>
|
||||
<CalendarCourseCell
|
||||
courseDeptAndInstr={courseDeptAndInstr}
|
||||
timeAndLocation={timeAndLocation}
|
||||
status={status}
|
||||
colors={block.course.colors}
|
||||
onClick={() => setCourse(block.course)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<div
|
||||
key={`${JSON.stringify(block)}`}
|
||||
style={{
|
||||
gridColumn: `${block.calendarGridPoint.dayIndex + 3}`,
|
||||
gridRow: `${block.calendarGridPoint.startIndex} / ${block.calendarGridPoint.endIndex}`,
|
||||
width: `calc(100% / ${block.totalColumns ?? 1})`,
|
||||
marginLeft: `calc(100% * ${((block.gridColumnStart ?? 0) - 1) / (block.totalColumns ?? 1)})`,
|
||||
}}
|
||||
className='pb-1 pl-0 pr-2.5 pt-0 screenshot:pb-0.5 screenshot:pr-0.5'
|
||||
>
|
||||
<CalendarCourseCell
|
||||
courseDeptAndInstr={courseDeptAndInstr}
|
||||
timeAndLocation={timeAndLocation}
|
||||
status={status}
|
||||
colors={block.course.colors}
|
||||
onClick={() => setCourse(block.course)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user