diff --git a/frontend/src/app/Plan/index.tsx b/frontend/src/app/Plan/index.tsx
index dab143e44..b7a12a853 100644
--- a/frontend/src/app/Plan/index.tsx
+++ b/frontend/src/app/Plan/index.tsx
@@ -104,8 +104,6 @@ export default function Plan() {
};
}, []);
- console.log(terms);
-
return (
diff --git a/frontend/src/app/Schedule/Calendar/Calendar.module.scss b/frontend/src/app/Schedule/Calendar/Calendar.module.scss
index 9b6401a3f..d98f2f811 100644
--- a/frontend/src/app/Schedule/Calendar/Calendar.module.scss
+++ b/frontend/src/app/Schedule/Calendar/Calendar.module.scss
@@ -16,19 +16,6 @@
line-height: 1;
z-index: 2;
- .timeZone {
- height: 32px;
- width: 64px;
- display: flex;
- align-items: center;
- justify-content: flex-end;
- padding: 0 12px;
- border-right: 1px solid var(--border-color);
- position: sticky;
- left: 0;
- background-color: var(--background-color);
- }
-
.week {
display: grid;
grid-template-columns: repeat(7, 1fr);
@@ -49,77 +36,7 @@
.view {
display: flex;
+ flex-direction: column;
z-index: 1;
-
- .week {
- flex-grow: 1;
- display: grid;
- grid-template-columns: repeat(7, 1fr);
-
- .day {
- position: relative;
-
- &:not(:last-child) {
- border-right: 1px solid var(--border-color);
- }
-
- .line {
- position: absolute;
- z-index: 1;
- left: -1px;
- width: calc(100% + 1px);
- height: 1px;
- background-color: var(--red-500);
- }
-
- .hour {
- height: 60px;
- display: flex;
- align-items: center;
- justify-content: center;
-
- &:not(:first-child) {
- border-top: 1px solid var(--border-color);
- }
- }
- }
- }
-
- .sideBar {
- flex-shrink: 0;
- width: 64px;
- display: flex;
- flex-direction: column;
- position: sticky;
- left: 0;
- z-index: 2;
- background-color: var(--background-color);
- border-right: 1px solid var(--border-color);
-
- .time {
- position: absolute;
- z-index: 1;
- height: 24px;
- display: flex;
- align-items: center;
- padding: 0 12px;
- font-size: 12px;
- color: white;
- line-height: 1;
- border-radius: 4px;
- right: 0;
- background-color: var(--red-500);
- }
-
- .hour {
- height: 0;
- margin-top: 60px;
- padding: 0 12px;
- font-size: 12px;
- color: var(--label-color);
- text-align: right;
- transform: translateY(-6px);
- }
- }
}
}
\ No newline at end of file
diff --git a/frontend/src/app/Schedule/Calendar/Week/Day/Day.module.scss b/frontend/src/app/Schedule/Calendar/Week/Day/Day.module.scss
new file mode 100644
index 000000000..5bf0825cd
--- /dev/null
+++ b/frontend/src/app/Schedule/Calendar/Week/Day/Day.module.scss
@@ -0,0 +1,54 @@
+.root {
+ aspect-ratio: 1;
+ padding: 8px;
+ display: flex;
+ flex-direction: column;
+ font-size: 12px;
+ line-height: 1;
+ gap: 4px;
+ overflow: hidden;
+
+ &:not(:last-child) {
+ border-right: 1px solid var(--border-color);
+ }
+
+ .event {
+ display: flex;
+ align-items: center;
+ padding: 0 8px;
+ border-radius: 4px;
+ gap: 8px;
+ height: 24px;
+ white-space: nowrap;
+
+ &.active {
+ opacity: 0.5;
+ }
+
+ .time {
+ color: rgb(255 255 255 / 75%);
+ font-size: 8px;
+ }
+
+ .course {
+ color: white;
+ font-weight: 500;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+ }
+
+ .date {
+ display: flex;
+
+ .month {
+ color: var(--heading-color);
+ font-weight: 500;
+ }
+
+ .number {
+ margin-left: auto;
+ color: var(--label-color);
+ }
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/Schedule/Calendar/Week/Day/index.tsx b/frontend/src/app/Schedule/Calendar/Week/Day/index.tsx
new file mode 100644
index 000000000..96815d6e9
--- /dev/null
+++ b/frontend/src/app/Schedule/Calendar/Week/Day/index.tsx
@@ -0,0 +1,55 @@
+import classNames from "classnames";
+
+import { getColor } from "@/lib/section";
+
+import { IDay } from "../../semester";
+import styles from "./Day.module.scss";
+
+const parseTime = (time: string) => {
+ const [hours, minutes] = time.split(":").map(Number);
+
+ let _time = `${hours % 12 || 12}`;
+ if (minutes > 0) _time += `:${minutes.toString().padStart(2, "0")}`;
+ _time += hours < 12 ? " AM" : " PM";
+
+ return _time;
+};
+
+interface DayProps extends IDay {
+ active: boolean;
+}
+
+export default function Day({ date, events, active }: DayProps) {
+ return (
+
+ {active && (
+
+ {date.format("D") === "1" && (
+
{date.format("MMMM")}
+ )}
+
{date.format("D")}
+
+ )}
+ {events.map((event) => (
+
+
+ {parseTime(event.meetings[0].startTime)}
+
+
+ {event.course.subject} {event.course.number}
+
+
+ ))}
+
+ );
+}
diff --git a/frontend/src/app/Schedule/Calendar/Week/Week.module.scss b/frontend/src/app/Schedule/Calendar/Week/Week.module.scss
new file mode 100644
index 000000000..cbe972758
--- /dev/null
+++ b/frontend/src/app/Schedule/Calendar/Week/Week.module.scss
@@ -0,0 +1,34 @@
+.root {
+ display: flex;
+ flex-direction: column;
+
+ &:not(:first-child) {
+ border-top: 1px solid var(--border-color);
+ }
+
+ &.dead {
+ background-color: var(--slate-100);
+ }
+
+ &.finals {
+ background-color: white;
+ }
+
+ .header {
+ font-size: 12px;
+ line-height: 1;
+ height: 32px;
+ color: var(--paragraph-color);
+ padding: 0 12px;
+ display: flex;
+ gap: 12px;
+ align-items: center;
+ border-bottom: 1px solid var(--border-color);
+ }
+
+ .body {
+ flex-grow: 1;
+ display: grid;
+ grid-template-columns: repeat(7, 1fr);
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/Schedule/Calendar/Week/index.tsx b/frontend/src/app/Schedule/Calendar/Week/index.tsx
new file mode 100644
index 000000000..e0a7ec3f6
--- /dev/null
+++ b/frontend/src/app/Schedule/Calendar/Week/index.tsx
@@ -0,0 +1,43 @@
+import classNames from "classnames";
+import { ArrowDown } from "iconoir-react";
+import moment from "moment";
+
+import { IDay } from "../semester";
+import Day from "./Day";
+import styles from "./Week.module.scss";
+
+interface WeekProps {
+ days: IDay[];
+ finals: boolean;
+ dead: boolean;
+ first: moment.Moment;
+ last: moment.Moment;
+}
+
+export default function Week({ days, finals, dead, first, last }: WeekProps) {
+ return (
+
+ {(dead || finals) && (
+
+
+ {dead ? "Reading, Review, and Recitation (RRR)" : "Finals"} week
+
+ )}
+
+ {days.map(({ date, events }) => (
+
+ ))}
+
+
+ );
+}
diff --git a/frontend/src/app/Schedule/Calendar/index.tsx b/frontend/src/app/Schedule/Calendar/index.tsx
index 6bb762631..7d89fec3c 100644
--- a/frontend/src/app/Schedule/Calendar/index.tsx
+++ b/frontend/src/app/Schedule/Calendar/index.tsx
@@ -1,47 +1,12 @@
-import { MouseEvent, useMemo, useRef, useState } from "react";
+import { useMemo, useState } from "react";
-import { ISection } from "@/lib/api";
-import { getY } from "@/lib/schedule";
-
-import styles from "./Calendar.module.scss";
-import Event from "./Event";
-
-const getId = (section: ISection) =>
- `${section.course.subject} ${section.course.number} ${section.class.number} ${section.number}`;
-
-// You have to trust me on this math
-const adjustAttachedEvents = (
- relevantSections: ISection[],
- attachedSections: string[],
- minutes: string[][],
- positions: Record
-) => {
- const adjustedSections: string[] = [];
-
- const adjustSection = (id: string) => {
- if (adjustedSections.includes(id)) return;
-
- adjustedSections.push(id);
-
- positions[id][1]++;
+import moment from "moment";
- const section = relevantSections.find((section) => id === getId(section));
- if (!section) return;
-
- const top = getY(section.meetings[0].startTime);
- const height = getY(section.meetings[0].endTime) - top;
-
- for (let i = top; i < top + height; i++) {
- for (const id of minutes[i]) {
- adjustSection(id);
- }
- }
- };
+import { ISection } from "@/lib/api";
- for (const id of attachedSections) {
- adjustSection(id);
- }
-};
+import styles from "./Semester.module.scss";
+import Week from "./Week";
+import { IDay } from "./semester";
interface CalendarProps {
selectedSections: ISection[];
@@ -52,122 +17,68 @@ export default function Calendar({
selectedSections,
currentSection,
}: CalendarProps) {
- const viewRef = useRef(null);
- const [y, setY] = useState(null);
-
const sections = useMemo(
() =>
currentSection ? [...selectedSections, currentSection] : selectedSections,
[selectedSections, currentSection]
);
- const days = useMemo(
- () =>
- [...Array(7)].map((_, day) => {
- const positions: Record = {};
- const minutes: string[][] = [...Array(60 * 18)].map(() => []);
-
- const relevantSections = sections
- // Filter sections for the current day which have a time specified
- .filter(
- (section) =>
- section.meetings[0].days[day] &&
- section.meetings[0].startTime &&
- getY(section.meetings[0].startTime) > 0
- )
- // Sort sections by when they start
- .sort(
- (a, b) =>
- getY(a.meetings[0].startTime) - getY(b.meetings[0].startTime)
- );
-
- // Maintain an array of sections that are attached to each minute
- for (const section of relevantSections) {
- const top = getY(section.meetings[0].startTime);
- const height = getY(section.meetings[0].endTime) - top;
-
- const attachedSections = minutes[top];
-
- let position = 0;
-
- while (
- attachedSections.findIndex(
- (eventId) => positions[eventId][0] === position
- ) !== -1
- ) {
- position++;
- }
-
- if (
- attachedSections.length > 0 &&
- Math.max(
- position,
- ...attachedSections.map((eventId) => positions[eventId][0])
- ) === position
- ) {
- adjustAttachedEvents(
- relevantSections,
- attachedSections,
- minutes,
- positions
- );
- }
-
- const id = getId(section);
-
- positions[id] = [
- position,
- attachedSections.length === 0
- ? 1
- : positions[attachedSections[0]][1],
- ];
-
- for (let i = top; i < top + height; i++) {
- minutes[i].push(id);
- }
- }
-
- return relevantSections.map((section) => {
- const [position, columns] = positions[getId(section)];
-
- return {
- ...section,
- position,
- active: section.ccn !== currentSection?.ccn,
- columns,
- };
- });
- }),
- [sections, currentSection]
- );
-
- const currentTime = useMemo(() => {
- if (!viewRef.current || !y) return;
-
- const hour = (Math.floor(y / 60) + 6) % 12 || 12;
- const minute = Math.floor(y % 60);
-
- return `${hour}:${minute < 10 ? `0${minute}` : minute}`;
- }, [y]);
-
- const updateY = (event: MouseEvent) => {
- if (!viewRef.current) return;
+ const [first] = useState(() => moment("2024-01-01"));
+ const [last] = useState(() => moment("2024-05-31"));
+
+ const [start] = useState(() => {
+ const current = moment("2024-01-01");
+ current.subtract(current.day(), "days");
+ return current;
+ });
+
+ const [stop] = useState(() => {
+ const stop = moment("2024-05-31");
+ stop.add(6 - stop.day(), "days");
+ return stop;
+ });
+
+ const weeks = useMemo(() => {
+ const weeks: IDay[][] = [];
+
+ const current = moment(start);
+
+ while (current.isSameOrBefore(stop)) {
+ const week = [];
+
+ for (let i = 0; i < 7; i++) {
+ const day = {
+ date: moment(current),
+ events: sections
+ .filter(
+ ({ startDate, endDate, meetings }) =>
+ current.isSameOrAfter(startDate) &&
+ current.isSameOrBefore(endDate) &&
+ meetings[0]?.days[current.day()]
+ )
+ .sort((a, b) =>
+ a.meetings[0].startTime.localeCompare(b.meetings[0].startTime)
+ )
+ .map((section) => ({
+ ...section,
+ active: section.ccn === currentSection?.ccn,
+ })),
+ };
+
+ week.push(day);
+
+ current.add(1, "days");
+ }
- const y = Math.max(
- 15,
- Math.min(
- event.clientY - viewRef.current.getBoundingClientRect().top,
- viewRef.current.clientHeight - 15
- )
- );
+ weeks.push(week);
+ }
- setY(y);
- };
+ return weeks;
+ }, [sections, currentSection, start, stop]);
return (
-
PST
Sunday
Monday
@@ -178,40 +89,19 @@ export default function Calendar({
Saturday
-
setY(null)}
- >
-
- {currentTime && y && (
-
- {currentTime}
-
- )}
- {[...Array(17)].map((_, hour) => (
-
- {hour + 7 < 12
- ? `${hour + 7} AM`
- : `${hour + 7 === 12 ? 12 : hour - 5} PM`}
-
- ))}
-
-
- {days.map((events, day) => (
-
- {[...Array(18)].map((_, hour) => (
-
- ))}
- {events.map((event) => (
-
- ))}
- {y &&
}
-
- ))}
-
+
+ {weeks.map((days, index) => {
+ return (
+
+ );
+ })}
);
diff --git a/frontend/src/app/Schedule/Calendar/semester.ts b/frontend/src/app/Schedule/Calendar/semester.ts
new file mode 100644
index 000000000..d156625d5
--- /dev/null
+++ b/frontend/src/app/Schedule/Calendar/semester.ts
@@ -0,0 +1,10 @@
+import { ISection } from "@/lib/api";
+
+interface IEvent extends ISection {
+ active?: boolean;
+}
+
+export interface IDay {
+ date: moment.Moment;
+ events: IEvent[];
+}
diff --git a/frontend/src/app/Schedule/Schedule/Event/Event.module.scss b/frontend/src/app/Schedule/Schedule/Event/Event.module.scss
new file mode 100644
index 000000000..fbb8078f9
--- /dev/null
+++ b/frontend/src/app/Schedule/Schedule/Event/Event.module.scss
@@ -0,0 +1,50 @@
+.trigger {
+ position: absolute;
+ z-index: 2;
+ padding: 8px;
+ border-radius: 4px;
+ background-color: var(--blue-500);
+ font-size: 12px;
+ opacity: 0.5;
+
+ &.active {
+ opacity: 1;
+ }
+
+ .heading {
+ font-weight: 500;
+ color: white;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+
+ .description {
+ margin-top: 4px;
+ color: rgb(255 255 255 / 75%);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+}
+
+.content {
+ height: 128px;
+ width: 320px;
+ background-color: var(--foreground-color);
+ border-radius: 8px;
+ box-shadow: 0 0 16px rgb(0 0 0 / 10%);
+ z-index: 989;
+ opacity: 0;
+ animation: fadeIn 100ms ease-in-out forwards;
+
+ .arrow {
+ fill: var(--foreground-color);
+ }
+}
+
+@keyframes fadeIn {
+ to {
+ opacity: 1;
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/Schedule/Schedule/Event/index.tsx b/frontend/src/app/Schedule/Schedule/Event/index.tsx
new file mode 100644
index 000000000..423ce3663
--- /dev/null
+++ b/frontend/src/app/Schedule/Schedule/Event/index.tsx
@@ -0,0 +1,62 @@
+import { useMemo } from "react";
+
+import * as HoverCard from "@radix-ui/react-hover-card";
+import classNames from "classnames";
+
+import { ISection } from "@/lib/api";
+import { getY } from "@/lib/schedule";
+import { getColor } from "@/lib/section";
+
+import styles from "./Event.module.scss";
+
+interface EventProps {
+ columns: number;
+ position: number;
+ active: boolean;
+}
+
+export default function Event({
+ columns,
+ position,
+ meetings: [{ startTime, endTime }],
+ course,
+ component,
+ number,
+ active,
+}: EventProps & ISection) {
+ const top = useMemo(() => getY(startTime!), [startTime]);
+
+ const height = useMemo(() => getY(endTime!) - top + 1, [top, endTime]);
+
+ // TODO: Hover card content
+ return (
+
+
+
+
+ {course.subject} {course.number}
+
+
+ {component} {number}
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/app/Schedule/Schedule/Schedule.module.scss b/frontend/src/app/Schedule/Schedule/Schedule.module.scss
new file mode 100644
index 000000000..9b6401a3f
--- /dev/null
+++ b/frontend/src/app/Schedule/Schedule/Schedule.module.scss
@@ -0,0 +1,125 @@
+.root {
+ display: flex;
+ flex-direction: column;
+ background-color: var(--background-color);
+ min-width: 1080px;
+
+ .header {
+ display: flex;
+ border-bottom: 1px solid var(--border-color);
+ position: sticky;
+ top: 0;
+ background-color: var(--background-color);
+ z-index: 1;
+ font-size: 12px;
+ color: var(--label-color);
+ line-height: 1;
+ z-index: 2;
+
+ .timeZone {
+ height: 32px;
+ width: 64px;
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ padding: 0 12px;
+ border-right: 1px solid var(--border-color);
+ position: sticky;
+ left: 0;
+ background-color: var(--background-color);
+ }
+
+ .week {
+ display: grid;
+ grid-template-columns: repeat(7, 1fr);
+ flex-grow: 1;
+
+ .day {
+ height: 32px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ &:not(:last-child) {
+ border-right: 1px solid var(--border-color);
+ }
+ }
+ }
+ }
+
+ .view {
+ display: flex;
+ z-index: 1;
+
+ .week {
+ flex-grow: 1;
+ display: grid;
+ grid-template-columns: repeat(7, 1fr);
+
+ .day {
+ position: relative;
+
+ &:not(:last-child) {
+ border-right: 1px solid var(--border-color);
+ }
+
+ .line {
+ position: absolute;
+ z-index: 1;
+ left: -1px;
+ width: calc(100% + 1px);
+ height: 1px;
+ background-color: var(--red-500);
+ }
+
+ .hour {
+ height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ &:not(:first-child) {
+ border-top: 1px solid var(--border-color);
+ }
+ }
+ }
+ }
+
+ .sideBar {
+ flex-shrink: 0;
+ width: 64px;
+ display: flex;
+ flex-direction: column;
+ position: sticky;
+ left: 0;
+ z-index: 2;
+ background-color: var(--background-color);
+ border-right: 1px solid var(--border-color);
+
+ .time {
+ position: absolute;
+ z-index: 1;
+ height: 24px;
+ display: flex;
+ align-items: center;
+ padding: 0 12px;
+ font-size: 12px;
+ color: white;
+ line-height: 1;
+ border-radius: 4px;
+ right: 0;
+ background-color: var(--red-500);
+ }
+
+ .hour {
+ height: 0;
+ margin-top: 60px;
+ padding: 0 12px;
+ font-size: 12px;
+ color: var(--label-color);
+ text-align: right;
+ transform: translateY(-6px);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/Schedule/Schedule/index.tsx b/frontend/src/app/Schedule/Schedule/index.tsx
new file mode 100644
index 000000000..04e185fda
--- /dev/null
+++ b/frontend/src/app/Schedule/Schedule/index.tsx
@@ -0,0 +1,218 @@
+import { MouseEvent, useMemo, useRef, useState } from "react";
+
+import { ISection } from "@/lib/api";
+import { getY } from "@/lib/schedule";
+
+import Event from "./Event";
+import styles from "./Schedule.module.scss";
+
+const getId = (section: ISection) =>
+ `${section.course.subject} ${section.course.number} ${section.class.number} ${section.number}`;
+
+// You have to trust me on this math
+const adjustAttachedEvents = (
+ relevantSections: ISection[],
+ attachedSections: string[],
+ minutes: string[][],
+ positions: Record
+) => {
+ const adjustedSections: string[] = [];
+
+ const adjustSection = (id: string) => {
+ if (adjustedSections.includes(id)) return;
+
+ adjustedSections.push(id);
+
+ positions[id][1]++;
+
+ const section = relevantSections.find((section) => id === getId(section));
+ if (!section) return;
+
+ const top = getY(section.meetings[0].startTime);
+ const height = getY(section.meetings[0].endTime) - top;
+
+ for (let i = top; i < top + height; i++) {
+ for (const id of minutes[i]) {
+ adjustSection(id);
+ }
+ }
+ };
+
+ for (const id of attachedSections) {
+ adjustSection(id);
+ }
+};
+
+interface CalendarProps {
+ selectedSections: ISection[];
+ currentSection: ISection | null;
+}
+
+export default function Schedule({
+ selectedSections,
+ currentSection,
+}: CalendarProps) {
+ const viewRef = useRef(null);
+ const [y, setY] = useState(null);
+
+ const sections = useMemo(
+ () =>
+ currentSection ? [...selectedSections, currentSection] : selectedSections,
+ [selectedSections, currentSection]
+ );
+
+ const days = useMemo(
+ () =>
+ [...Array(7)].map((_, day) => {
+ const positions: Record = {};
+ const minutes: string[][] = [...Array(60 * 18)].map(() => []);
+
+ const relevantSections = sections
+ // Filter sections for the current day which have a time specified
+ .filter(
+ (section) =>
+ section.meetings[0].days[day] &&
+ section.meetings[0].startTime &&
+ getY(section.meetings[0].startTime) > 0
+ )
+ // Sort sections by when they start
+ .sort(
+ (a, b) =>
+ getY(a.meetings[0].startTime) - getY(b.meetings[0].startTime)
+ );
+
+ // Maintain an array of sections that are attached to each minute
+ for (const section of relevantSections) {
+ const top = getY(section.meetings[0].startTime);
+ const height = getY(section.meetings[0].endTime) - top;
+
+ const attachedSections = minutes[top];
+
+ let position = 0;
+
+ while (
+ attachedSections.findIndex(
+ (eventId) => positions[eventId][0] === position
+ ) !== -1
+ ) {
+ position++;
+ }
+
+ if (
+ attachedSections.length > 0 &&
+ Math.max(
+ position,
+ ...attachedSections.map((eventId) => positions[eventId][0])
+ ) === position
+ ) {
+ adjustAttachedEvents(
+ relevantSections,
+ attachedSections,
+ minutes,
+ positions
+ );
+ }
+
+ const id = getId(section);
+
+ positions[id] = [
+ position,
+ attachedSections.length === 0
+ ? 1
+ : positions[attachedSections[0]][1],
+ ];
+
+ for (let i = top; i < top + height; i++) {
+ minutes[i].push(id);
+ }
+ }
+
+ return relevantSections.map((section) => {
+ const [position, columns] = positions[getId(section)];
+
+ return {
+ ...section,
+ position,
+ active: section.ccn !== currentSection?.ccn,
+ columns,
+ };
+ });
+ }),
+ [sections, currentSection]
+ );
+
+ const currentTime = useMemo(() => {
+ if (!viewRef.current || !y) return;
+
+ const hour = (Math.floor(y / 60) + 6) % 12 || 12;
+ const minute = Math.floor(y % 60);
+
+ return `${hour}:${minute < 10 ? `0${minute}` : minute}`;
+ }, [y]);
+
+ const updateY = (event: MouseEvent) => {
+ if (!viewRef.current) return;
+
+ const y = Math.max(
+ 15,
+ Math.min(
+ event.clientY - viewRef.current.getBoundingClientRect().top,
+ viewRef.current.clientHeight - 15
+ )
+ );
+
+ setY(y);
+ };
+
+ return (
+
+
+
PST
+
+
Sunday
+
Monday
+
Tuesday
+
Wednesday
+
Thursday
+
Friday
+
Saturday
+
+
+
setY(null)}
+ >
+
+ {currentTime && y && (
+
+ {currentTime}
+
+ )}
+ {[...Array(17)].map((_, hour) => (
+
+ {hour + 7 < 12
+ ? `${hour + 7} AM`
+ : `${hour + 7 === 12 ? 12 : hour - 5} PM`}
+
+ ))}
+
+
+ {days.map((events, day) => (
+
+ {[...Array(18)].map((_, hour) => (
+
+ ))}
+ {events.map((event) => (
+
+ ))}
+ {y &&
}
+
+ ))}
+
+
+
+ );
+}
diff --git a/frontend/src/app/Schedule/SideBar/Class/Section/index.tsx b/frontend/src/app/Schedule/SideBar/Class/Section/index.tsx
index b4ff91586..d371e0023 100644
--- a/frontend/src/app/Schedule/SideBar/Class/Section/index.tsx
+++ b/frontend/src/app/Schedule/SideBar/Class/Section/index.tsx
@@ -36,8 +36,8 @@ export default function Section({
{number}