Skip to content

feat(schedule): add configurable day-start hour - #463

Open
chiptus wants to merge 2 commits into
mainfrom
feat-86/festival-day-start-hour
Open

chiptus wants to merge 2 commits into
mainfrom
feat-86/festival-day-start-hour

Conversation

@chiptus

@chiptus chiptus commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Adds festivals.day_start_hour (0-23, default 0) so a festival can fold post-midnight sets into the previous festival day instead of always splitting at exact midnight. Widens the existing day-key seam (getFestivalDayKey/formatDayOnly) and threads the cutoff through schedule grouping, the day filter, the days reveal level, and the horizontal timeline's day boundaries/jump targets.

Closes #86

Verification

  • Set a festival's day-start hour to 0 (default): schedule list, timeline, day filter, and reveal-level day labels render identically to before.
  • Set a festival's day-start hour to 6 in the festival edit dialog: a ~02:00 set moves under the previous festival day in both the list and the horizontal timeline; the day filter and the days-reveal display agree; the day header reads the previous date.
  • Confirm the day filter dropdown offers the shifted day as an option (not just the edition's raw calendar-date range).
  • pnpm run typecheck, pnpm run lint, pnpm exec vitest run, and pnpm run build all pass.

Note: the issue's spec mentioned following "the existing react-hook-form pattern" in the festival edit dialog, but that dialog (FestivalDialog.tsx) actually uses plain useState, not react-hook-form — the new field follows the file's actual existing pattern instead.


Generated by Claude Code

Copilot AI lite review requested due to automatic review settings August 29, 2026 16:17
@vercel

vercel Bot commented Aug 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
upline Ready Ready Preview Oct 15, 2026 7:57am UTC

@chiptus chiptus added the agent:pr label Aug 29, 2026 — with Claude
@github-actions

github-actions Bot commented Aug 29, 2026 •

Copy link
Copy Markdown

Deploy → staging — workflow run
Last updated: 2026-10-15 07:58:52 UTC

  • ✅ DB migrations succeeded
  • ✅ Edge functions succeeded
  • ⏭️ Type generation skipped (no changes)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The current dayStartHour implementation in src/lib/timeUtils.ts shifts instants in UTC before timezone formatting, which can misclassify festival days around DST transitions.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds a per-festival day_start_hour cutoff (defaulting to midnight) so post-midnight sets can be grouped/labelled under the previous “festival day”, and threads that cutoff through schedule grouping, day filtering, reveal-level day labels, and the horizontal timeline’s day boundaries/jump behavior.

Changes:

  • Adds festivals.day_start_hour (0–23, default 0) to the database schema and Supabase generated types, and wires it into festival create/update flows and the admin festival edit dialog.
  • Extends the “festival day key” seam (getFestivalDayKey / formatDayOnly) and propagates dayStartHour through schedule list/timeline grouping, timeline geometry/boundaries/jump targets, and active-day detection.
  • Reworks day-filter option generation to include a leading shifted day when a cutoff is configured, and adds unit tests across the updated time/day utilities.
File summaries
File Description
supabase/migrations/20260829160000_add_festival_day_start_hour.sql Adds day_start_hour column + range check constraint on festivals.
src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline.tsx Passes festival.day_start_hour into schedule/timeline data and container.
src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule/list.tsx Threads dayStartHour through list schedule grouping and memo deps.
src/pages/SetDetails/SetInfoCard.tsx Uses formatDayOnly(..., day_start_hour) for reveal-level day display.
src/pages/SetDetails/NonMusicSetDetail/NonMusicSetBanner.tsx Uses formatDayOnly(..., day_start_hour) for reveal-level day display.
src/pages/SetDetails/MultiArtistSetInfoCard.tsx Uses formatDayOnly(..., day_start_hour) for reveal-level day display.
src/pages/EditionView/tabs/VoteTab/SetCard/SetMetadata.tsx Uses formatDayOnly(..., day_start_hour) for reveal-level day display.
src/pages/EditionView/tabs/ScheduleTab/horizontal/timeScaleGeometry.ts Makes date-change detection use festival-day keys with dayStartHour.
src/pages/EditionView/tabs/ScheduleTab/horizontal/timeScaleGeometry.test.ts Adds unit test for cutoff folding behavior in date-change detection.
src/pages/EditionView/tabs/ScheduleTab/horizontal/TimeScaleContainer.tsx Adds dayStartHour prop and passes it to TimeScale.
src/pages/EditionView/tabs/ScheduleTab/horizontal/TimeScale.tsx Passes dayStartHour to computeDateChanges.
src/pages/EditionView/tabs/ScheduleTab/horizontal/TimelineToolbar.tsx Threads dayStartHour into day jump controls.
src/pages/EditionView/tabs/ScheduleTab/horizontal/TimelineOverview.tsx Threads dayStartHour into day-boundary calculation.
src/pages/EditionView/tabs/ScheduleTab/horizontal/TimelineContainer.tsx Adds dayStartHour prop and threads into scroll sync / overview / scale.
src/pages/EditionView/tabs/ScheduleTab/horizontal/DayJumpButtons.tsx Passes dayStartHour into getDayJumpMoment.
src/pages/EditionView/tabs/ScheduleTab/DayFilterSelect.tsx Switches to buildDayFilterOptions(...) and includes festival cutoff.
src/pages/admin/festivals/FestivalDialog.tsx Adds admin UI input for day_start_hour with clamping (0–23).
src/lib/timeUtils.ts Extends festival-day key/label utilities and introduces festivalDayStart.
src/lib/timeUtils.test.ts Adds tests for cutoff behavior in getFestivalDayKey and formatDayOnly.
src/lib/timelineOverviewGeometry.ts Uses festivalDayStart for boundary placement with cutoff support.
src/lib/timelineOverviewGeometry.test.ts Adds/updates tests for cutoff-aware boundary placement.
src/lib/timelineMountMoment.ts Makes timeline mount moment resolve day-start using cutoff-aware boundary.
src/lib/timelineMountMoment.test.ts Adds tests for cutoff-aware mount moment behavior.
src/lib/timelineDayJump.ts Makes day jump fallback use cutoff-aware day start instead of midnight.
src/lib/timelineDayJump.test.ts Adds test for cutoff-aware day jump fallback.
src/lib/dayFilterOptions.ts New helper to build day-filter options, adding leading shifted day if needed.
src/lib/dayFilterOptions.test.ts Unit tests for new day-filter option builder behavior.
src/integrations/supabase/types.ts Updates generated DB types to include festivals.day_start_hour.
src/hooks/useTimelineScrollSync.ts Threads dayStartHour into timeline mount-moment resolution.
src/hooks/useScheduleData.ts Uses cutoff-aware festival day keys when grouping sets into schedule days.
src/hooks/useActiveTimelineDay.ts Uses cutoff-aware day jump moments when computing active day offsets.
src/api/festivals/useUpdateFestival.ts Allows updating day_start_hour via mutation typing.
src/api/festivals/useCreateFestival.ts Allows setting day_start_hour on create via mutation typing.
docs/adr/0002-festival-timezone-display.md Updates ADR to reflect the now-implemented configurable cutoff.
Review details

Suppressed comments (1)

src/lib/timeUtils.ts:208

  • dayStartHour is defined in the festival's timezone, but the current implementation shifts the UTC instant with subHours before formatting in the target timezone. Around DST transitions this can produce the wrong festival-day key (e.g., after a spring-forward, subtracting N hours in UTC can subtract N±1 hours in local time), misgrouping sets and timeline day boundaries.
// festival's day rather than the viewer's. `dayStartHour` (0-23, the
// festival's configured day-start cutoff) shifts the instant back by that
// many hours first, so sets before the cutoff fold into the previous
// festival day instead of splitting at exact midnight.
  • Files reviewed: 34/34 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/lib/timeUtils.ts
@github-actions

github-actions Bot commented Aug 29, 2026 •

Copy link
Copy Markdown

Playwright test results

passed  68 passed

Details

stats  68 tests across 22 suites
duration  1 minute, 31 seconds
commit  1c8b53a

chiptus pushed a commit that referenced this pull request Sep 13, 2026
Replaces the two lifecycle labels with a single `agent` label whose
stage is read off the issue's native Linear status (In Progress while
claimed, In Review once the PR is open) instead of a second label.
Retired agent:wip/agent:pr in Linear (team UPL) and migrated the one
live issue carrying agent:pr (UPL-7, open PR #463) to
the new scheme. Also updates the setup-chiptus-env Linear template to
match; the GitHub template is unchanged since GitHub issues have no
native per-issue status to borrow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HFNqcr5d2EN6T6TkTc8WBd

chiptus commented Sep 28, 2026

Copy link
Copy Markdown
Owner Author

Merged main in to resolve a conflict in list.tsx — main's day-grouping refactor (using filterScheduleDays/scheduleDays[].date) already produces the cutoff-aware day key via useScheduleData's internal getFestivalDayKey(..., dayStartHour), so this branch's now-redundant manual re-grouping block (using getFestivalDayKey directly on each slot) was dropped in favor of main's simpler version; also dropped the now-unused festival.day_start_hour dep the lint step flagged. pnpm run lint, pnpm run build:dev, and pnpm test all pass locally after the merge.

The Require staging label for migrations check is still red — this PR touches supabase/migrations/** and needs the staging label to pass that gate. The staging label is off-limits for the agent pipeline to apply, so this is waiting on you to add it before merge.


Generated by Claude Code

Comment thread src/hooks/useScheduleData.ts Outdated
Comment thread src/hooks/useScheduleData.ts Outdated
Comment thread src/hooks/useScheduleReveal.ts
Comment thread src/lib/timeUtils.ts Outdated
Comment thread src/pages/admin/festivals/FestivalDialog.tsx Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Day grouping remains inconsistent in the fallback lineup and timeline labels, and the UTC subtraction misclassifies cutoff boundaries across DST transitions.

4 open findings
1 resolved since last review

🧠 Review effort: Balanced

Comment thread src/pages/EditionView/tabs/ScheduleTab/horizontal/TimeScale.tsx
Comment thread src/pages/admin/festivals/FestivalDialog.tsx Outdated
Comment thread src/pages/admin/festivals/DayEndHourField.tsx Outdated
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CJJoJtCsdZVQLeGBiN5Vnb
Timeline date bands now split at real midnight, the fallback lineup honours
the festival cutoff, and the festival form tests cover day_end_hour.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CJJoJtCsdZVQLeGBiN5Vnb

This branch was successfully deployed

2 active deployments
staging — 1c8b53a5 Deployed Oct 15, 2026 by chiptus via types / Regenerate types (staging) #145
Preview — 1c8b53a5 Deployed Oct 15, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configurable festival "day end" hour so post-midnight sets group with the previous night

3 participants