Loading more courses...
diff --git a/apps/web/src/modules/course-selection/components/CourseSectionItem.tsx b/apps/web/src/modules/course-selection/components/CourseSectionItem.tsx
index 5f59e60c..7e1b3acb 100644
--- a/apps/web/src/modules/course-selection/components/CourseSectionItem.tsx
+++ b/apps/web/src/modules/course-selection/components/CourseSectionItem.tsx
@@ -58,8 +58,16 @@ export const CourseSectionItem = ({
{offering.instructors.join(", ")}
- {offering.days.map((day) => day.slice(0, 3).toUpperCase()).join(", ")}{" "}
- {offering.startTime} - {offering.endTime}
+ {offering.startTime && offering.endTime ? (
+ <>
+ {offering.days
+ .map((day) => day.slice(0, 3).toUpperCase())
+ .join(", ")}{" "}
+ {offering.startTime} - {offering.endTime}
+ >
+ ) : (
+ Time not available yet
+ )}
{offering.location ?? "TBD"}
diff --git a/apps/web/src/modules/schedule-calendar/schedule-calendar.tsx b/apps/web/src/modules/schedule-calendar/schedule-calendar.tsx
index ae422a6e..bf197593 100644
--- a/apps/web/src/modules/schedule-calendar/schedule-calendar.tsx
+++ b/apps/web/src/modules/schedule-calendar/schedule-calendar.tsx
@@ -34,8 +34,8 @@ export interface Class {
term: Term;
instructors: string[];
location?: string;
- startTime: string;
- endTime: string;
+ startTime: string | undefined;
+ endTime: string | undefined;
status: "open" | "closed" | "waitlist";
waitlistNum?: number;
isCorequisite: boolean;
@@ -112,92 +112,101 @@ export function ScheduleCalendar({
return ;
}
- const transformedClasses: Class[] = classes.map((c) => {
- const offering = c.courseOffering;
- const startTime = `${offering.startTime.split(":")[0]} ${offering.startTime.split(":")[1]}`;
- const endTime = `${offering.endTime.split(":")[0]} ${offering.endTime.split(":")[1]}`;
+ const transformedClasses: Class[] = classes
+ .filter((c) => {
+ const offering = c.courseOffering;
+ return offering.startTime && offering.endTime;
+ })
+ .map((c) => {
+ const offering = c.courseOffering;
+ // biome-ignore lint/style/noNonNullAssertion: we just filtered above
+ const startTime = `${offering.startTime!.split(":")[0]} ${offering.startTime!.split(":")[1]}`;
+ // biome-ignore lint/style/noNonNullAssertion: we just filtered above
+ const endTime = `${offering.endTime!.split(":")[0]} ${offering.endTime!.split(":")[1]}`;
- // Format times like "Monday 9 15 11 15"
- const times = offering.days.map((day) => {
- const dayName = day.charAt(0).toUpperCase() + day.slice(1);
- return `${dayName} ${startTime} ${endTime}`;
- });
+ // Format times like "Monday 9 15 11 15"
+ const times = offering.days.map((day) => {
+ const dayName = day.charAt(0).toUpperCase() + day.slice(1);
+ return `${dayName} ${startTime} ${endTime}`;
+ });
- const color = getColor(offering._id);
+ const color = getColor(offering._id);
- const slots: { start: Date; end: Date }[] = [];
+ const slots: { start: Date; end: Date }[] = [];
- // Map weekday names to 0-6 offset from start of week (Sunday = 0)
- const weekdayMap: Record = {
- Sunday: 0,
- Monday: 1,
- Tuesday: 2,
- Wednesday: 3,
- Thursday: 4,
- Friday: 5,
- Saturday: 6,
- };
+ // Map weekday names to 0-6 offset from start of week (Sunday = 0)
+ const weekdayMap: Record = {
+ Sunday: 0,
+ Monday: 1,
+ Tuesday: 2,
+ Wednesday: 3,
+ Thursday: 4,
+ Friday: 5,
+ Saturday: 6,
+ };
- // Get the start of the current week (Sunday)
- const startOfCurrentWeek = startOfWeek(new Date(), { weekStartsOn: 0 }); // Sunday = 0
+ // Get the start of the current week (Sunday)
+ const startOfCurrentWeek = startOfWeek(new Date(), { weekStartsOn: 0 }); // Sunday = 0
- for (const slot of times) {
- const parts = slot.split(" ");
- const day = parts[0];
- const startHour = Number(parts[1]);
- const startMinute = Number(parts[2]);
- const endHour = Number(parts[3]);
- const endMinute = Number(parts[4]);
+ for (const slot of times) {
+ const parts = slot.split(" ");
+ const day = parts[0];
+ const startHour = Number(parts[1]);
+ const startMinute = Number(parts[2]);
+ const endHour = Number(parts[3]);
+ const endMinute = Number(parts[4]);
- const dayOffset = weekdayMap[day];
- if (dayOffset === undefined) {
- throw new Error(`Invalid day: ${day}`);
- }
+ const dayOffset = weekdayMap[day];
+ if (dayOffset === undefined) {
+ throw new Error(`Invalid day: ${day}`);
+ }
- const date = addDays(startOfCurrentWeek, dayOffset);
+ const date = addDays(startOfCurrentWeek, dayOffset);
- const start = new Date(date);
- start.setHours(startHour, startMinute, 0, 0);
+ const start = new Date(date);
+ start.setHours(startHour, startMinute, 0, 0);
- const end = new Date(date);
- end.setHours(endHour, endMinute, 0, 0);
+ const end = new Date(date);
+ end.setHours(endHour, endMinute, 0, 0);
- slots.push({ start, end });
- }
+ slots.push({ start, end });
+ }
- return {
- id: offering._id,
- userCourseOfferingId: c._id,
- classNumber: c.classNumber,
- courseCode: offering.courseCode,
- title: `${offering.courseCode} - ${offering.title}`,
- color,
- times: slots,
- description: `${offering.instructors.join(", ")} • ${offering.section.toUpperCase()} • ${offering.term} ${offering.year}`,
- section: offering.section,
- year: offering.year,
- term: offering.term,
- instructors: offering.instructors,
- location: offering.location,
- startTime: offering.startTime,
- endTime: offering.endTime,
- status: offering.status,
- waitlistNum: offering.waitlistNum,
- isCorequisite: offering.isCorequisite,
- corequisiteOf: offering.corequisiteOf,
- };
- });
+ return {
+ id: offering._id,
+ userCourseOfferingId: c._id,
+ classNumber: c.classNumber,
+ courseCode: offering.courseCode,
+ title: `${offering.courseCode} - ${offering.title}`,
+ color,
+ times: slots,
+ description: `${offering.instructors.join(", ")} • ${offering.section.toUpperCase()} • ${offering.term} ${offering.year}`,
+ section: offering.section,
+ year: offering.year,
+ term: offering.term,
+ instructors: offering.instructors,
+ location: offering.location,
+ startTime: offering.startTime,
+ endTime: offering.endTime,
+ status: offering.status,
+ waitlistNum: offering.waitlistNum,
+ isCorequisite: offering.isCorequisite,
+ corequisiteOf: offering.corequisiteOf,
+ };
+ });
// Add hovered course preview
- if (hoveredCourse) {
+ if (hoveredCourse?.startTime && hoveredCourse.endTime) {
const isAlreadyAdded = classes.some(
(c) => c.courseOffering._id === hoveredCourse._id,
);
if (!isAlreadyAdded) {
const offering = hoveredCourse;
- const startTime = `${offering.startTime.split(":")[0]} ${offering.startTime.split(":")[1]}`;
- const endTime = `${offering.endTime.split(":")[0]} ${offering.endTime.split(":")[1]}`;
+ // biome-ignore lint/style/noNonNullAssertion: we just filtered above
+ const startTime = `${offering.startTime!.split(":")[0]} ${offering.startTime!.split(":")[1]}`;
+ // biome-ignore lint/style/noNonNullAssertion: we just filtered above
+ const endTime = `${offering.endTime!.split(":")[0]} ${offering.endTime!.split(":")[1]}`;
const times = offering.days.map((day) => {
const dayName = day.charAt(0).toUpperCase() + day.slice(1);
@@ -248,8 +257,8 @@ export function ScheduleCalendar({
term: offering.term,
instructors: offering.instructors,
location: offering.location,
- startTime: offering.startTime,
- endTime: offering.endTime,
+ startTime: offering.startTime as string,
+ endTime: offering.endTime as string,
status: offering.status,
waitlistNum: offering.waitlistNum,
isCorequisite: offering.isCorequisite,
diff --git a/packages/server/convex/http.ts b/packages/server/convex/http.ts
index 902b97f8..02adb242 100644
--- a/packages/server/convex/http.ts
+++ b/packages/server/convex/http.ts
@@ -105,7 +105,7 @@ export const ZUpsertCourseWithPrerequisites = z.object({
export const ZUpsertProgramWithRequirements = z.object({
name: z.string(),
- level: ZSchoolLevel,
+ level: ZSchoolLevel, // undergraduate or graduate
school: ZSchoolName,
programUrl: z.string(),
requirements: z.array(
@@ -130,7 +130,7 @@ export const ZUpsertProgramWithRequirements = z.object({
courseLevels: z.array(
z.object({
program: z.string(), // CSCI-UA
- level: z.coerce.number(), // 4
+ level: z.coerce.number(), // 4 (represents any classes at 400 level)
}),
),
creditsRequired: z.number(),
diff --git a/packages/server/convex/schemas/courseOfferings.ts b/packages/server/convex/schemas/courseOfferings.ts
index 5fd3f96d..ea9dc725 100644
--- a/packages/server/convex/schemas/courseOfferings.ts
+++ b/packages/server/convex/schemas/courseOfferings.ts
@@ -29,8 +29,8 @@ const courseOfferings = {
v.literal("sunday"),
),
),
- startTime: v.string(), // 13:00
- endTime: v.string(), // 14:15
+ startTime: v.optional(v.string()), // 13:00
+ endTime: v.optional(v.string()), // 14:15
status: v.union(
v.literal("open"),
v.literal("closed"),