fix: fixed bug with course cells after 12 PM extending past midnight (#122)
* Temporarily uninstalling husky cause github desktop has issues with it * Cleaned up some code. Removed unnecessary state value on injected popup * Should've fixed popup alignment issue. Still need to integrate course schedule with calendar. Still debugging. * Updated CalendarGridStories * Fix: change to ExampleCourse from exampleCourse * setCourse and calendar header need work * Update as part of merge * Fix: fixed build errors * Fix: Added Todo * Chore: Cleaned up useFlattenedCourseSchedule hook * fix: List now keeps track of state when existing items are switched, while adding new items to the end * Added back husky * Update src/views/components/calendar/Calendar/Calendar.tsx Co-authored-by: doprz <52579214+doprz@users.noreply.github.com> * refactor: added type-safety, destructuring, etc. ready for re-review * refactor: got rid of ts-ignore in openNewTabFromContentScript * Update src/views/components/calendar/CalendarHeader/CalenderHeader.tsx Co-authored-by: doprz <52579214+doprz@users.noreply.github.com> * refactor: using path aliasing Co-authored-by: doprz <52579214+doprz@users.noreply.github.com> * refactor: using path aliasing Co-authored-by: doprz <52579214+doprz@users.noreply.github.com> * refactor: using satisfies instead of as Co-authored-by: doprz <52579214+doprz@users.noreply.github.com> * refactor: using satisfies instead of as Co-authored-by: doprz <52579214+doprz@users.noreply.github.com> * style: reformatted spacing * style: eslint import order * refactor: added new constructor for UserSchedule to avoid passing down null values to child props * fix: fixed bug with course cell times starting and after 12 PM. commented in CourseMeeting class * Update src/views/hooks/useFlattenedCourseSchedule.ts * fix: fixed build errors by removing old apis * refactor: added type-safety and destructuring --------- Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
This commit is contained in:
11000
pnpm-lock.yaml
generated
11000
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -31,9 +31,13 @@ export type Location = {
|
|||||||
export class CourseMeeting {
|
export class CourseMeeting {
|
||||||
/** The day of the week that the course is taught */
|
/** The day of the week that the course is taught */
|
||||||
days: Day[];
|
days: Day[];
|
||||||
/** The start time of the course, in minutes since midnight */
|
/** NOTE: Times starting and after 12 PM have an additional 720 minutes (12 hrs) added to them
|
||||||
|
* The start time of the course, in minutes since midnight
|
||||||
|
* */
|
||||||
startTime: number;
|
startTime: number;
|
||||||
/** The end time of the course, in minutes since midnight */
|
/** NOTE: Times starting and after 12 PM have an additional 720 minutes (12 hrs) added to them
|
||||||
|
* The end time of the course, in minutes since midnight
|
||||||
|
* */
|
||||||
endTime: number;
|
endTime: number;
|
||||||
/** The location that the course is taught */
|
/** The location that the course is taught */
|
||||||
location?: Location;
|
location?: Location;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ const meta = {
|
|||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
},
|
},
|
||||||
argTypes: {
|
argTypes: {
|
||||||
dummySchedules: { control: 'object' },
|
// dummySchedules: { control: 'object' },
|
||||||
dummyActiveIndex: { control: 'number' },
|
// dummyActiveIndex: { control: 'number' },
|
||||||
},
|
},
|
||||||
render: (args: any) => (
|
render: (args: any) => (
|
||||||
<div>
|
<div>
|
||||||
@@ -138,7 +138,7 @@ const schedules = [
|
|||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
dummySchedules: schedules,
|
// dummySchedules: schedules,
|
||||||
dummyActiveIndex: 0,
|
// dummyActiveIndex: 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,99 +11,99 @@ const exampleSchedule: UserSchedule = new UserSchedule({
|
|||||||
});
|
});
|
||||||
// TODO (achadaga): import this after
|
// TODO (achadaga): import this after
|
||||||
// https://github.com/Longhorn-Developers/UT-Registration-Plus/pull/106 is merged
|
// https://github.com/Longhorn-Developers/UT-Registration-Plus/pull/106 is merged
|
||||||
const bevoCourse: Course = new Course({
|
// const bevoCourse: Course = new Course({
|
||||||
uniqueId: 47280,
|
// uniqueId: 47280,
|
||||||
number: '311C',
|
// number: '311C',
|
||||||
fullName: "BVO 311C BEVO'S SEMINAR LONGHORN CARE",
|
// fullName: "BVO 311C BEVO'S SEMINAR LONGHORN CARE",
|
||||||
courseName: "BEVO'S SEMINAR LONGHORN CARE",
|
// courseName: "BEVO'S SEMINAR LONGHORN CARE",
|
||||||
department: 'BVO',
|
// department: 'BVO',
|
||||||
creditHours: 3,
|
// creditHours: 3,
|
||||||
status: Status.OPEN,
|
// status: Status.OPEN,
|
||||||
instructors: [new Instructor({ fullName: 'BEVO', firstName: '', lastName: 'BEVO', middleInitial: '' })],
|
// instructors: [new Instructor({ fullName: 'BEVO', firstName: '', lastName: 'BEVO', middleInitial: '' })],
|
||||||
isReserved: false,
|
// isReserved: false,
|
||||||
description: [
|
// description: [
|
||||||
'Restricted to Students in the School of Longhorn Enthusiasts',
|
// 'Restricted to Students in the School of Longhorn Enthusiasts',
|
||||||
'Immerse yourself in the daily routine of a longhorn—sunrise pasture walks and the best shady spots for a midday siesta. Understand the behavioral science behind our mascot’s stoic demeanor during games.',
|
// 'Immerse yourself in the daily routine of a longhorn—sunrise pasture walks and the best shady spots for a midday siesta. Understand the behavioral science behind our mascot’s stoic demeanor during games.',
|
||||||
'BVO 311C and 312H may not both be counted.',
|
// 'BVO 311C and 312H may not both be counted.',
|
||||||
'Prerequisite: Grazing 311 or 311H.',
|
// 'Prerequisite: Grazing 311 or 311H.',
|
||||||
'May be counted toward the Independent Inquiry flag requirement. May be counted toward the Writing flag requirement',
|
// 'May be counted toward the Independent Inquiry flag requirement. May be counted toward the Writing flag requirement',
|
||||||
'Offered on the letter-grade basis only.',
|
// 'Offered on the letter-grade basis only.',
|
||||||
],
|
// ],
|
||||||
schedule: new CourseSchedule({
|
// schedule: new CourseSchedule({
|
||||||
meetings: [
|
// meetings: [
|
||||||
new CourseMeeting({
|
// new CourseMeeting({
|
||||||
days: ['Tuesday', 'Thursday'],
|
// days: ['Tuesday', 'Thursday'],
|
||||||
startTime: 480,
|
// startTime: 480,
|
||||||
endTime: 570,
|
// endTime: 570,
|
||||||
location: { building: 'UTC', room: '123' },
|
// location: { building: 'UTC', room: '123' },
|
||||||
}),
|
// }),
|
||||||
new CourseMeeting({
|
// new CourseMeeting({
|
||||||
days: ['Thursday'],
|
// days: ['Thursday'],
|
||||||
startTime: 570,
|
// startTime: 570,
|
||||||
endTime: 630,
|
// endTime: 630,
|
||||||
location: { building: 'JES', room: '123' },
|
// location: { building: 'JES', room: '123' },
|
||||||
}),
|
// }),
|
||||||
],
|
// ],
|
||||||
}),
|
// }),
|
||||||
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20242/12345/',
|
// url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20242/12345/',
|
||||||
flags: ['Independent Inquiry', 'Writing'],
|
// flags: ['Independent Inquiry', 'Writing'],
|
||||||
instructionMode: 'In Person',
|
// instructionMode: 'In Person',
|
||||||
semester: {
|
// semester: {
|
||||||
code: '12345',
|
// code: '12345',
|
||||||
year: 2024,
|
// year: 2024,
|
||||||
season: 'Spring',
|
// season: 'Spring',
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
const meta = {
|
// const meta = {
|
||||||
title: 'Components/Injected/CourseCatalogInjectedPopup',
|
// title: 'Components/Injected/CourseCatalogInjectedPopup',
|
||||||
component: CourseCatalogInjectedPopup,
|
// component: CourseCatalogInjectedPopup,
|
||||||
args: {
|
// args: {
|
||||||
course: exampleCourse,
|
// course: exampleCourse,
|
||||||
activeSchedule: exampleSchedule,
|
// activeSchedule: exampleSchedule,
|
||||||
onClose: () => {},
|
// onClose: () => {},
|
||||||
},
|
// },
|
||||||
argTypes: {
|
// argTypes: {
|
||||||
course: {
|
// course: {
|
||||||
control: {
|
// control: {
|
||||||
type: 'object',
|
// type: 'object',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
activeSchedule: {
|
// activeSchedule: {
|
||||||
control: {
|
// control: {
|
||||||
type: 'object',
|
// type: 'object',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
onClose: {
|
// onClose: {
|
||||||
control: {
|
// control: {
|
||||||
type: 'function',
|
// type: 'function',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
} satisfies Meta<typeof CourseCatalogInjectedPopup>;
|
// } satisfies Meta<typeof CourseCatalogInjectedPopup>;
|
||||||
|
|
||||||
export default meta;
|
// export default meta;
|
||||||
type Story = StoryObj<typeof meta>;
|
// type Story = StoryObj<typeof meta>;
|
||||||
|
|
||||||
export const OpenCourse: Story = {
|
// export const OpenCourse: Story = {
|
||||||
args: {
|
// args: {
|
||||||
course: exampleCourse,
|
// course: exampleCourse,
|
||||||
activeSchedule: exampleSchedule,
|
// activeSchedule: exampleSchedule,
|
||||||
onClose: () => {},
|
// onClose: () => {},
|
||||||
},
|
// },
|
||||||
};
|
// };
|
||||||
|
|
||||||
export const ClosedCourse: Story = {
|
// export const ClosedCourse: Story = {
|
||||||
args: {
|
// args: {
|
||||||
course: {
|
// course: {
|
||||||
...exampleCourse,
|
// ...exampleCourse,
|
||||||
status: Status.CLOSED,
|
// status: Status.CLOSED,
|
||||||
} satisfies Course,
|
// } satisfies Course,
|
||||||
},
|
// },
|
||||||
};
|
// };
|
||||||
|
|
||||||
export const CourseWithNoData: Story = {
|
// export const CourseWithNoData: Story = {
|
||||||
args: {
|
// args: {
|
||||||
course: bevoCourse,
|
// course: bevoCourse,
|
||||||
},
|
// },
|
||||||
};
|
// };
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ interface Props {
|
|||||||
* Grid of CalendarGridCell components forming the user's course schedule calendar view
|
* Grid of CalendarGridCell components forming the user's course schedule calendar view
|
||||||
* @param props
|
* @param props
|
||||||
*/
|
*/
|
||||||
// function CalendarGrid({ courseCells, saturdayClass }: React.PropsWithChildren<Props>): JSX.Element {
|
|
||||||
// const [grid, setGrid] = useState([]);
|
|
||||||
function CalendarGrid({ courseCells, saturdayClass, setCourse }: React.PropsWithChildren<Props>): JSX.Element {
|
function CalendarGrid({ courseCells, saturdayClass, setCourse }: React.PropsWithChildren<Props>): JSX.Element {
|
||||||
// const [grid, setGrid] = useState([]);
|
// const [grid, setGrid] = useState([]);
|
||||||
const calendarRef = useRef(null); // Create a ref for the calendar grid
|
const calendarRef = useRef(null); // Create a ref for the calendar grid
|
||||||
@@ -152,29 +150,33 @@ function AccountForCourseConflicts({ courseCells, setCourse }: AccountForCourseC
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Part of TODO: block.course is definitely a course object
|
// Part of TODO: block.course is definitely a course object
|
||||||
console.log(courseCells);
|
// console.log(courseCells);
|
||||||
|
|
||||||
|
return courseCells.map((block, i) => {
|
||||||
|
const { courseDeptAndInstr, timeAndLocation, status, colors } = courseCells[i].componentProps;
|
||||||
|
|
||||||
return courseCells.map(block => (
|
return (
|
||||||
<div
|
<div
|
||||||
key={`${block}`}
|
key={`${block}`}
|
||||||
style={{
|
style={{
|
||||||
gridColumn: `${block.calendarGridPoint.dayIndex + 2}`,
|
gridColumn: `${block.calendarGridPoint.dayIndex + 2}`,
|
||||||
gridRow: `${block.calendarGridPoint.startIndex} / ${block.calendarGridPoint.endIndex}`,
|
gridRow: `${block.calendarGridPoint.startIndex} / ${block.calendarGridPoint.endIndex}`,
|
||||||
width: `calc(100% / ${block.totalColumns})`,
|
width: `calc(100% / ${block.totalColumns})`,
|
||||||
marginLeft: `calc(100% * ${(block.gridColumnStart - 1) / block.totalColumns})`,
|
marginLeft: `calc(100% * ${(block.gridColumnStart - 1) / block.totalColumns})`,
|
||||||
padding: '0px 10px 4px 0px',
|
padding: '0px 10px 4px 0px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CalendarCourseCell
|
<CalendarCourseCell
|
||||||
courseDeptAndInstr={block.componentProps.courseDeptAndInstr}
|
courseDeptAndInstr={courseDeptAndInstr}
|
||||||
timeAndLocation={block.componentProps.timeAndLocation}
|
timeAndLocation={timeAndLocation}
|
||||||
status={block.componentProps.status}
|
status={status}
|
||||||
// TODO: Change to block.componentProps.colors when colors are integrated to the rest of the project
|
// TODO: Change to block.componentProps.colors when colors are integrated to the rest of the project
|
||||||
colors={getCourseColors('emerald', 500) /* block.componentProps.colors */}
|
colors={getCourseColors('emerald', 500) /* block.componentProps.colors */}
|
||||||
onClick={() => setCourse(block.course)}
|
onClick={() => setCourse(block.course)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
));
|
)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* <div className={styles.buttonContainer}>
|
/* <div className={styles.buttonContainer}>
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ const handleOpenOptions = async () => {
|
|||||||
await openTabFromContentScript(url);
|
await openTabFromContentScript(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CalendarHeader = ({ totalHours, totalCourses, scheduleName }) => (
|
const CalendarHeader = ( { totalHours, totalCourses, scheduleName } ) => (
|
||||||
<div className='min-h-79px min-w-672px w-full flex px-0'>
|
<div className='min-h-79px min-w-672px w-full flex px-0 py-15'>
|
||||||
<div className='flex flex-row gap-20'>
|
<div className='flex flex-row gap-20'>
|
||||||
<div className='flex gap-10'>
|
<div className='flex gap-10'>
|
||||||
<div className='flex gap-1'>
|
<div className='flex gap-1'>
|
||||||
@@ -49,7 +49,7 @@ const CalendarHeader = ({ totalHours, totalCourses, scheduleName }) => (
|
|||||||
<div className='flex flex-row'>
|
<div className='flex flex-row'>
|
||||||
<Button variant='single' icon={UndoIcon} color='ut-black' />
|
<Button variant='single' icon={UndoIcon} color='ut-black' />
|
||||||
<Button variant='single' icon={RedoIcon} color='ut-black' />
|
<Button variant='single' icon={RedoIcon} color='ut-black' />
|
||||||
<Button variant='single' icon={SettingsIcon} color='ut-black' onClick={handleOpenOptions} />
|
<Button variant='single' icon={SettingsIcon} color='ut-black' onClick={handleOpenOptions}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ const List: React.FC<ListProps> = ({ draggableElements, itemHeight, listHeight,
|
|||||||
return [...prevItems, ...newItems];
|
return [...prevItems, ...newItems];
|
||||||
});
|
});
|
||||||
}, [draggableElements]);
|
}, [draggableElements]);
|
||||||
|
|
||||||
const onDragEnd = useCallback(
|
const onDragEnd = useCallback(
|
||||||
result => {
|
result => {
|
||||||
if (!result.destination) {
|
if (!result.destination) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default function CourseCatalogInjectedPopup({
|
|||||||
<Popup overlay className='max-w-[780px] px-6' onClose={onClose}>
|
<Popup overlay className='max-w-[780px] px-6' onClose={onClose}>
|
||||||
<div className='flex flex-col'>
|
<div className='flex flex-col'>
|
||||||
<HeadingAndActions course={course} onClose={onClose} activeSchedule={activeSchedule} />
|
<HeadingAndActions course={course} onClose={onClose} activeSchedule={activeSchedule} />
|
||||||
<Description lines={course.description} />
|
<Description course={course} /* lines={course.description} Looks like this was replaced. Description now set internally*/ />
|
||||||
<GradeDistribution course={course} />
|
<GradeDistribution course={course} />
|
||||||
</div>
|
</div>
|
||||||
</Popup>
|
</Popup>
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ const HeadingAndActions: React.FC<HeadingAndActionProps> = ({
|
|||||||
onClose,
|
onClose,
|
||||||
}: HeadingAndActionProps): JSX.Element => {
|
}: HeadingAndActionProps): JSX.Element => {
|
||||||
const { courseName, department, number: courseNumber, uniqueId, instructors, flags, schedule } = course;
|
const { courseName, department, number: courseNumber, uniqueId, instructors, flags, schedule } = course;
|
||||||
const [courseAdded, setCourseAdded] = useState<boolean>(
|
const courseAdded = activeSchedule.courses.some(ourCourse => ourCourse.uniqueId === uniqueId);
|
||||||
activeSchedule !== undefined ? activeSchedule.courses.some(course => course.uniqueId === uniqueId) : false
|
|
||||||
);
|
|
||||||
|
|
||||||
const getInstructorFullName = (instructor: Instructor) => {
|
const getInstructorFullName = (instructor: Instructor) => {
|
||||||
const { firstName, lastName } = instructor;
|
const { firstName, lastName } = instructor;
|
||||||
@@ -105,7 +103,6 @@ const HeadingAndActions: React.FC<HeadingAndActionProps> = ({
|
|||||||
} else {
|
} else {
|
||||||
removeCourse({ course, scheduleName: activeSchedule.name });
|
removeCourse({ course, scheduleName: activeSchedule.name });
|
||||||
}
|
}
|
||||||
setCourseAdded(prev => !prev);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import type { CalendarCourseCellProps } from '@views/components/calendar/Calenda
|
|||||||
|
|
||||||
import useSchedules from './useSchedules';
|
import useSchedules from './useSchedules';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const dayToNumber: { [day: string]: number } = {
|
const dayToNumber: { [day: string]: number } = {
|
||||||
Monday: 0,
|
Monday: 0,
|
||||||
Tuesday: 1,
|
Tuesday: 1,
|
||||||
@@ -58,32 +60,31 @@ export function useFlattenedCourseSchedule(): FlattenedCourseSchedule {
|
|||||||
return {
|
return {
|
||||||
courseCells: [] as CalendarGridCourse[],
|
courseCells: [] as CalendarGridCourse[],
|
||||||
activeSchedule: new UserSchedule([], 'Something may have went wrong', 0),
|
activeSchedule: new UserSchedule([], 'Something may have went wrong', 0),
|
||||||
} as FlattenedCourseSchedule;
|
} satisfies FlattenedCourseSchedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeSchedule.courses.length === 0) {
|
if (activeSchedule.courses.length === 0) {
|
||||||
return {
|
return {
|
||||||
courseCells: [] as CalendarGridCourse[],
|
courseCells: [] as CalendarGridCourse[],
|
||||||
activeSchedule,
|
activeSchedule
|
||||||
} satisfies FlattenedCourseSchedule;
|
} satisfies FlattenedCourseSchedule;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { courses, name, hours } = activeSchedule;
|
const { courses, name, hours } = activeSchedule;
|
||||||
|
|
||||||
const processedCourses = courses
|
const processedCourses = courses.flatMap((course: Course) => {
|
||||||
.flatMap((course: Course) => {
|
const { status, courseDeptAndInstr, meetings } = extractCourseInfo(course);
|
||||||
const { status, courseDeptAndInstr, meetings } = extractCourseInfo(course);
|
|
||||||
|
if (meetings.length === 0) {
|
||||||
if (meetings.length === 0) {
|
return processAsyncCourses({ courseDeptAndInstr, status, course });
|
||||||
return processAsyncCourses({ courseDeptAndInstr, status, course });
|
}
|
||||||
}
|
|
||||||
|
return meetings.flatMap((meeting: CourseMeeting) =>
|
||||||
return meetings.flatMap((meeting: CourseMeeting) =>
|
processInPersonMeetings(meeting, { courseDeptAndInstr, status, course })
|
||||||
processInPersonMeetings(meeting, { courseDeptAndInstr, status, course })
|
);
|
||||||
);
|
}).sort(sortCourses);
|
||||||
})
|
|
||||||
.sort(sortCourses);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
courseCells: processedCourses as CalendarGridCourse[],
|
courseCells: processedCourses as CalendarGridCourse[],
|
||||||
activeSchedule: { name, courses, hours } as UserSchedule,
|
activeSchedule: { name, courses, hours } as UserSchedule,
|
||||||
@@ -105,33 +106,23 @@ function extractCourseInfo(course: Course) {
|
|||||||
/**
|
/**
|
||||||
* Function to process each in-person class into its distinct meeting objects for calendar grid
|
* Function to process each in-person class into its distinct meeting objects for calendar grid
|
||||||
*/
|
*/
|
||||||
function processAsyncCourses({
|
function processAsyncCourses({ courseDeptAndInstr, status, course }: { courseDeptAndInstr: string, status: StatusType, course: Course }) {
|
||||||
courseDeptAndInstr,
|
return [{
|
||||||
status,
|
calendarGridPoint: {
|
||||||
course,
|
dayIndex: 0,
|
||||||
}: {
|
startIndex: 0,
|
||||||
courseDeptAndInstr: string;
|
endIndex: 0,
|
||||||
status: StatusType;
|
|
||||||
course: Course;
|
|
||||||
}) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
calendarGridPoint: {
|
|
||||||
dayIndex: 0,
|
|
||||||
startIndex: 0,
|
|
||||||
endIndex: 0,
|
|
||||||
},
|
|
||||||
componentProps: {
|
|
||||||
courseDeptAndInstr,
|
|
||||||
status,
|
|
||||||
colors: {
|
|
||||||
primaryColor: 'ut-gray',
|
|
||||||
secondaryColor: 'ut-gray',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
course,
|
|
||||||
},
|
},
|
||||||
] satisfies CalendarGridCourse[];
|
componentProps: {
|
||||||
|
courseDeptAndInstr,
|
||||||
|
status,
|
||||||
|
colors: {
|
||||||
|
primaryColor: 'ut-gray',
|
||||||
|
secondaryColor: 'ut-gray',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
course,
|
||||||
|
}] satisfies CalendarGridCourse[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,13 +132,17 @@ function processInPersonMeetings(
|
|||||||
{ days, startTime, endTime, location }: CourseMeeting,
|
{ days, startTime, endTime, location }: CourseMeeting,
|
||||||
{ courseDeptAndInstr, status, course }
|
{ courseDeptAndInstr, status, course }
|
||||||
) {
|
) {
|
||||||
|
const midnightIndex = 1440;
|
||||||
|
const normalizingTimeFactor = 720;
|
||||||
const time = getTimeString({ separator: '-', capitalize: true }, startTime, endTime);
|
const time = getTimeString({ separator: '-', capitalize: true }, startTime, endTime);
|
||||||
const timeAndLocation = `${time} - ${location ? location.building : 'WB'}`;
|
const timeAndLocation = `${time} - ${location ? location.building : 'WB'}`;
|
||||||
|
let normalizedStartTime = startTime >= midnightIndex ? startTime - normalizingTimeFactor : startTime;
|
||||||
|
let normalizedEndTime = endTime >= midnightIndex ? endTime - normalizingTimeFactor : endTime;
|
||||||
return days.map(day => ({
|
return days.map(day => ({
|
||||||
calendarGridPoint: {
|
calendarGridPoint: {
|
||||||
dayIndex: dayToNumber[day],
|
dayIndex: dayToNumber[day],
|
||||||
startIndex: convertMinutesToIndex(startTime),
|
startIndex: convertMinutesToIndex(normalizedStartTime),
|
||||||
endIndex: convertMinutesToIndex(endTime),
|
endIndex: convertMinutesToIndex(normalizedEndTime),
|
||||||
},
|
},
|
||||||
componentProps: {
|
componentProps: {
|
||||||
courseDeptAndInstr,
|
courseDeptAndInstr,
|
||||||
@@ -165,7 +160,7 @@ function processInPersonMeetings(
|
|||||||
/**
|
/**
|
||||||
* Utility function to sort courses for the calendar grid
|
* Utility function to sort courses for the calendar grid
|
||||||
*/
|
*/
|
||||||
function sortCourses(a, b) {
|
function sortCourses(a: CalendarGridCourse, b: CalendarGridCourse): number {
|
||||||
const { dayIndex: dayIndexA, startIndex: startIndexA, endIndex: endIndexA } = a.calendarGridPoint;
|
const { dayIndex: dayIndexA, startIndex: startIndexA, endIndex: endIndexA } = a.calendarGridPoint;
|
||||||
const { dayIndex: dayIndexB, startIndex: startIndexB, endIndex: endIndexB } = b.calendarGridPoint;
|
const { dayIndex: dayIndexB, startIndex: startIndexB, endIndex: endIndexB } = b.calendarGridPoint;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user