Skip to content

Barebones schedule timeline component#240

Open
ExistentialKevin wants to merge 2 commits intodevfrom
scheduletimeline-bare
Open

Barebones schedule timeline component#240
ExistentialKevin wants to merge 2 commits intodevfrom
scheduletimeline-bare

Conversation

@ExistentialKevin
Copy link

@ExistentialKevin ExistentialKevin commented Mar 20, 2026

Why

  • A modular component allows developers to mix and match custom components with ease.

What

  • A simple component that groups up events based on the day of each event.
  • Provides a default header component for dates if no component is provided.
  • Timezone calculation is done by the component.
  • EventRow component can be passed in to change how the events are displayed.

Satisfies

HK-236

Summary by CodeRabbit

  • New Features
    • Added a new schedule display component that presents events organized by day of week in table format with improved timezone handling capabilities.

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

A new ScheduleTimelineBare React component was added that renders a schedule as an HTML table grouped by day of week. The component partitions events by day, computes user timezone with fallback logic, and renders day headers and event rows using composable sub-components.

Changes

Cohort / File(s) Summary
Schedule Timeline Component
apps/web/src/components/schedule/ScheduleTimelineBare.tsx
New component that renders schedule events grouped by day of week; includes splitByDay helper to partition events by day name, timezone computation with fallback to getClientTimeZone, and dynamic rendering of day headers and event rows via customizable sub-components.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • Issue #233 directly corresponds to this implementation, featuring the same ScheduleTimelineBare component, splitByDay logic, timezone handling, and composable header and event row rendering patterns.

Poem

🐰 A timeline bare, now polished and bright,
Events arranged by each day's delight,
Grouped by the week in a table so fine,
With timezones dancing in perfect align!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Barebones schedule timeline component' accurately describes the main change—adding a new minimal, modular schedule timeline component. It is concise, clear, and directly related to the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch scheduletimeline-bare
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can suggest fixes for GitHub Check annotations.

Configure the reviews.tools.github-checks setting to adjust the time to wait for GitHub Checks to complete.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/web/src/components/schedule/ScheduleTimelineBare.tsx (1)

27-34: Remove unnecessary key prop from component definition.

The key prop on line 29 has no effect here. React keys are meaningful when assigned to elements in the parent's render context (e.g., inside .map()), not inside the component definition itself.

♻️ Proposed fix
 const DefaultDayHeader = ({ dayName }: DayHeaderProps) => (
-	<tr key={dayName + " title"} className="border-b py-8">
+	<tr className="border-b py-8">
 		<td>
 			<h2 className="w-full px-4 py-4 text-5xl font-black">{dayName}</h2>
 		</td>
 	</tr>
 );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/schedule/ScheduleTimelineBare.tsx` around lines 27 -
34, The DefaultDayHeader component defines a static key on its returned <tr>
which is unused and should be removed; update the DefaultDayHeader (and its
DayHeaderProps usage) to return the <tr> without the key attribute (remove the
`key={dayName + " title"}` from DefaultDayHeader) so keys are only provided by
the parent when rendering lists.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/components/schedule/ScheduleTimelineBare.tsx`:
- Around line 56-69: The fragment returned inside days.map currently uses the
shorthand <>...</> which cannot accept a key; replace it with an explicit
React.Fragment and add a stable key (for example using dayName or a composite
like `${dayName}-${index}`) so React can reconcile correctly—update the fragment
wrapping DayHeader and the arr.map of RenderEventRow in the days.map callback to
use React.Fragment with that key while keeping DayHeader and RenderEventRow
unchanged (they still use event.id and userTimeZone).
- Around line 16-25: In splitByDay, event.startTime is a numeric timestamp so
calling .getDay() will fail; convert it to a Date first (e.g., const dayIndex =
new Date(event.startTime).getDay()) and use daysOfWeek[dayIndex] when computing
day; update the reference inside splitByDay (and any related uses of
event.startTime in that function) to use the Date-converted value so grouping
works correctly.

---

Nitpick comments:
In `@apps/web/src/components/schedule/ScheduleTimelineBare.tsx`:
- Around line 27-34: The DefaultDayHeader component defines a static key on its
returned <tr> which is unused and should be removed; update the DefaultDayHeader
(and its DayHeaderProps usage) to return the <tr> without the key attribute
(remove the `key={dayName + " title"}` from DefaultDayHeader) so keys are only
provided by the parent when rendering lists.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5c6425a8-8422-490a-9a47-caec347ce305

📥 Commits

Reviewing files that changed from the base of the PR and between 105d85c and 9639ad4.

📒 Files selected for processing (1)
  • apps/web/src/components/schedule/ScheduleTimelineBare.tsx

Comment on lines +16 to +25
function splitByDay(schedule: Event[]) {
const days: Map<string, Event[]> = new Map();
schedule.forEach((event) => {
const day = daysOfWeek[event.startTime.getDay()];
const existing = days.get(day);
if (existing) existing.push(event);
else days.set(day, [event]);
});
return days;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the database schema definition for the startTime field type
ast-grep --pattern 'startTime: $_'

# Also check how events are typically fetched to see if dates are already parsed
rg -n "startTime" --type ts -C 3 -g '!node_modules'

Repository: acmutsa/HackKit

Length of output: 13607


🏁 Script executed:

#!/bin/bash
# Find the Event type definition used in ScheduleTimelineBare.tsx
echo "=== Checking ScheduleTimelineBare.tsx imports and type definitions ==="
head -30 apps/web/src/components/schedule/ScheduleTimelineBare.tsx

echo -e "\n=== Searching for Event type definition ==="
rg "type Event\b|interface Event\b" --type ts

echo -e "\n=== Finding where splitByDay is called from ==="
rg "splitByDay" --type ts -B 3 -A 3

Repository: acmutsa/HackKit

Length of output: 3507


🏁 Script executed:

#!/bin/bash
# Find the EventType definition in lib/types/events.ts
echo "=== Full EventType definition ==="
cat apps/web/src/lib/types/events.ts

echo -e "\n=== Checking if Event is re-exported elsewhere ==="
rg "export.*Event" apps/web/src/lib/types/events.ts

Repository: acmutsa/HackKit

Length of output: 1288


🏁 Script executed:

#!/bin/bash
# Verify Drizzle ORM type inference for timestamp_ms mode
echo "=== Checking Drizzle documentation or code for timestamp_ms behavior ==="
rg "timestamp_ms|mode.*timestamp" --type ts -C 2

# Also check if there's any conversion happening in data fetching
echo -e "\n=== Checking getAllEvents function (main data fetcher) ==="
sed -n '20,35p' packages/db/functions/events.ts

Repository: acmutsa/HackKit

Length of output: 2988


Convert event.startTime to a Date before calling .getDay().

The startTime field is stored as an integer (milliseconds) in the database and typed as number by Drizzle ORM's timestamp_ms mode. Calling .getDay() directly will throw a runtime error. Convert it to a Date object first, as done elsewhere in the codebase (e.g., EventColumns.tsx):

Suggested fix:
 schedule.forEach((event) => {
-	const day = daysOfWeek[event.startTime.getDay()];
+	const day = daysOfWeek[new Date(event.startTime).getDay()];
📝 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
function splitByDay(schedule: Event[]) {
const days: Map<string, Event[]> = new Map();
schedule.forEach((event) => {
const day = daysOfWeek[event.startTime.getDay()];
const existing = days.get(day);
if (existing) existing.push(event);
else days.set(day, [event]);
});
return days;
}
function splitByDay(schedule: Event[]) {
const days: Map<string, Event[]> = new Map();
schedule.forEach((event) => {
const day = daysOfWeek[new Date(event.startTime).getDay()];
const existing = days.get(day);
if (existing) existing.push(event);
else days.set(day, [event]);
});
return days;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/schedule/ScheduleTimelineBare.tsx` around lines 16 -
25, In splitByDay, event.startTime is a numeric timestamp so calling .getDay()
will fail; convert it to a Date first (e.g., const dayIndex = new
Date(event.startTime).getDay()) and use daysOfWeek[dayIndex] when computing day;
update the reference inside splitByDay (and any related uses of event.startTime
in that function) to use the Date-converted value so grouping works correctly.

Comment on lines +56 to +69
{days.map(
([dayName, arr]): ReactNode => (
<>
<DayHeader dayName={dayName} />
{arr.map((event) => (
<RenderEventRow
key={event.id}
event={event}
userTimeZone={userTimeZone}
/>
))}
</>
),
)}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing key on React Fragment in .map() will cause warnings and reconciliation issues.

The shorthand fragment syntax <>...</> cannot accept a key prop. When rendering fragments inside .map(), you must use the explicit <React.Fragment key={...}> syntax.

🐛 Proposed fix
+import React from "react";

Then update the render:

 {days.map(
-  ([dayName, arr]): ReactNode => (
-    <>
+  ([dayName, arr]) => (
+    <React.Fragment key={dayName}>
       <DayHeader dayName={dayName} />
       {arr.map((event) => (
         <RenderEventRow
           key={event.id}
           event={event}
           userTimeZone={userTimeZone}
         />
       ))}
-    </>
+    </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
{days.map(
([dayName, arr]): ReactNode => (
<>
<DayHeader dayName={dayName} />
{arr.map((event) => (
<RenderEventRow
key={event.id}
event={event}
userTimeZone={userTimeZone}
/>
))}
</>
),
)}
{days.map(
([dayName, arr]) => (
<React.Fragment key={dayName}>
<DayHeader dayName={dayName} />
{arr.map((event) => (
<RenderEventRow
key={event.id}
event={event}
userTimeZone={userTimeZone}
/>
))}
</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/ScheduleTimelineBare.tsx` around lines 56 -
69, The fragment returned inside days.map currently uses the shorthand <>...</>
which cannot accept a key; replace it with an explicit React.Fragment and add a
stable key (for example using dayName or a composite like `${dayName}-${index}`)
so React can reconcile correctly—update the fragment wrapping DayHeader and the
arr.map of RenderEventRow in the days.map callback to use React.Fragment with
that key while keeping DayHeader and RenderEventRow unchanged (they still use
event.id and userTimeZone).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant