Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions apps/web/src/app/schedule/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import ScheduleTimeline from "../dash/schedule/schedule-timeline";
import ScheduleTable from "@/components/schedule/ScheduleTable";
import { getAllEvents } from "db/functions";
import { getClientTimeZone } from "@/lib/utils/client/shared";
import c from "config";

export default async function Page() {
const sched = await getAllEvents();
const userTimeZone = getClientTimeZone(c.hackathonTimezone);
return (
<>
<h1 className="mx-auto my-8 w-3/4 text-8xl font-black">Schedule</h1>
<ScheduleTimeline schedule={sched} timezone={userTimeZone} />
<h1 className="mx-auto my-8 w-11/12 lg:w-3/4 text-5xl font-black">Schedule</h1>
<ScheduleTable schedule={sched}/>
</>
);
}
Expand Down
146 changes: 146 additions & 0 deletions apps/web/src/components/schedule/ScheduleTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import {
Table,
TableBody,
TableCell,
TableHeader,
TableRow,
} from "@/components/shadcn/ui/table";

import { type EventType as Event } from "@/lib/types/events";
import { ReactNode } from "react";
import { formatInTimeZone } from "date-fns-tz";
import c from "config";
import { Badge } from "@/components/shadcn/ui/badge";
import Link from "next/link";

const userTimeZone = c.hackathonTimezone;

function splitByDay(schedule: Event[]) {
const days: Map<string, Event[]> = new Map<string, Event[]>();
schedule.forEach((event) => {
const day = daysOfWeek[event.startTime.getDay()];

if (days.get(day)) {
days.get(day)?.push(event);
} else {
days.set(day, [event]);
}
});
return days;
}

type ScheduleTableProps = {
schedule: Event[];

};

const daysOfWeek = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
function eventDateString(arr: Event[], timezone: string) {
const date = formatInTimeZone(arr[0].startTime, timezone, "PPPP");
const retString = date.substring(0, date.length - 6);
return retString;
}

export default function ScheduleTable({
schedule,
}: ScheduleTableProps) {
return (
<div className="mx-auto mt-5 w-[99vw] lg:w-3/4">
<Table className="grid gap-6">
{Array.from(splitByDay(schedule).entries()).map(
([dateID, arr]): ReactNode => (
<>
<TableBody key={dateID} className="border">
<TableHeader className="flex justify-start">
<span className="m-1 p-4 text-center text-xl font-bold lg:text-4xl">
<p>{`${eventDateString(arr, userTimeZone)}`}</p>
</span>
</TableHeader>
{arr.map(
(event): ReactNode => (
<EventRow
key={event.id}
event={event}
/>
),
)}
</TableBody>
</>
),
Comment on lines +58 to +77
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing key on Fragment causes React warning.

When mapping, the key should be on the outermost element. The fragment <> is outermost, but the key is on TableBody inside. Use React.Fragment with an explicit key instead.

Proposed fix
+import React, { type ReactNode } from "react";
-import { ReactNode } from "react";
 				{Array.from(splitByDay(schedule).entries()).map(
 					([dateID, arr]): ReactNode => (
-						<>
-							<TableBody key={dateID} className="border">
+						<React.Fragment key={dateID}>
+							<TableBody className="border">
 								<TableHeader className="flex justify-start">
 									<span className="m-1 p-4 text-center text-xl font-bold lg:text-4xl">
 										<p>{`${eventDateString(arr, userTimeZone)}`}</p>
 									</span>
 								</TableHeader>
 								{arr.map(
 									(event): ReactNode => (
 										<EventRow
 											key={event.id}
 											event={event}
 										/>
 									),
 								)}
 							</TableBody>
-						</>
+						</React.Fragment>
 					),
 				)}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{Array.from(splitByDay(schedule).entries()).map(
([dateID, arr]): ReactNode => (
<>
<TableBody key={dateID} className="border">
<TableHeader className="flex justify-start">
<span className="m-1 p-4 text-center text-xl font-bold lg:text-4xl">
<p>{`${eventDateString(arr, userTimeZone)}`}</p>
</span>
</TableHeader>
{arr.map(
(event): ReactNode => (
<EventRow
key={event.id}
event={event}
/>
),
)}
</TableBody>
</>
),
{Array.from(splitByDay(schedule).entries()).map(
([dateID, arr]): ReactNode => (
<React.Fragment key={dateID}>
<TableBody className="border">
<TableHeader className="flex justify-start">
<span className="m-1 p-4 text-center text-xl font-bold lg:text-4xl">
<p>{`${eventDateString(arr, userTimeZone)}`}</p>
</span>
</TableHeader>
{arr.map(
(event): ReactNode => (
<EventRow
key={event.id}
event={event}
/>
),
)}
</TableBody>
</React.Fragment>
),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/schedule/ScheduleTable.tsx` around lines 58 - 77, The
mapped fragment uses a shorthand <> but the key is placed on the inner TableBody
which causes a React "missing key on fragment" warning; change the outer
fragment to an explicit React.Fragment and move the key to that fragment (i.e.,
replace <> with React.Fragment key={dateID}) so the key is on the outermost
element returned from the Array.from(splitByDay(schedule).entries()).map
callback (referencing splitByDay, dateID, TableBody, and EventRow to locate the
code).

)}
</Table>
</div>
);
}

// Needs timezone prop
type eventRowProps = {
event: Event;
};
export function EventRow({ event }: eventRowProps) {
const startTimeFormatted = formatInTimeZone(
event.startTime,
userTimeZone,
"hh:mm a",
{
useAdditionalDayOfYearTokens: true,
},
);

const endTimeFormatted = formatInTimeZone(
event.endTime,
userTimeZone,
"h:mm a",
);
const color = (c.eventTypes as Record<string, string>)[event.type];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add fallback for unknown event types.

If event.type is not a key in c.eventTypes, color will be undefined and the badge border won't render. Add a fallback like EventDetails.tsx does (see apps/web/src/components/events/admin/EventDetails.tsx:17-18).

Proposed fix
-	const color = (c.eventTypes as Record<string, string>)[event.type];
+	const color = (c.eventTypes as Record<string, string>)[event.type] || c.eventTypes.Other;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const color = (c.eventTypes as Record<string, string>)[event.type];
const color = (c.eventTypes as Record<string, string>)[event.type] || c.eventTypes.Other;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/schedule/ScheduleTable.tsx` at line 103, The code
gets color via const color = (c.eventTypes as Record<string,
string>)[event.type] which can be undefined for unknown event.type; change this
to use a fallback (same approach used in EventDetails.tsx) so color defaults to
a safe value (e.g., an empty string or a default color key) when event.type is
not present in c.eventTypes; update the reference in ScheduleTable.tsx where
color is used (the badge border rendering) to rely on this fallback to ensure
the badge always renders.

const href = "/schedule/" + event.id;
return (
<TableRow
key={event.id}
className="flex flex-col justify-around bg-transparent px-4 pb-1 odd:bg-white/5"
>
<TableCell className="p-2 flex place-items-center">
<div className="w-1/3">
<Link href={href}>
<span className="flex font-semibold">
<p>{`${startTimeFormatted}`}</p>
<p className="hidden sm:contents">
{`- ${endTimeFormatted}`}
</p>
</span>
</Link>
</div>
<div className="flex w-2/3 place-items-center justify-end gap-2">
<Badge
variant={"outline"}
className="flex justify-center text-center lg:w-[5rem]"
style={{
borderColor: color,
}}
>
<p className="text-[0.5rem] lg:text-xs">{event.type}</p>
</Badge>

<Link href={href}>
<p className="p-1 text-right font-semibold lg:text-xl">
{`${event.title}`}
</p>
</Link>
</div>
</TableCell>
<TableCell className="hidden lg:contents">
<div className="p-2 w-full truncate text-ellipsis text-right">
<p>{`${event.description}`}</p>
</div>
</TableCell>
</TableRow>
);
}
2 changes: 1 addition & 1 deletion apps/web/src/components/shadcn/ui/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const TableCell = React.forwardRef<
<td
ref={ref}
className={cn(
"p-4 align-middle [&:has([role=checkbox])]:pr-0",
"align-middle [&:has([role=checkbox])]:pr-0",
className,
)}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/shared/NavBarLinksGrouper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default async function NavBarLinksGrouper() {
</NavbarItem>,
);
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix trailing whitespace causing Prettier CI failure.

Line 15 contains extra trailing whitespace after the closing brace. Please remove it (or run Prettier on the file) so Prettier --check passes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/shared/NavBarLinksGrouper.tsx` at line 15, Remove the
trailing whitespace after the closing brace in NavBarLinksGrouper.tsx (the extra
space following the '}' in the component/file) so Prettier passes; simply delete
the trailing spaces or run Prettier/format on the file (e.g., target the
NavBarLinksGrouper component/definition) and commit the formatted file.

return <>{toRender}</>;
}

Expand Down
Loading