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

feat(schedule): add configurable day-start hour#463
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

claude added 2 commits August 29, 2026 16:09
Add 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. Admin can set the
cutoff in the festival edit dialog.

Closes #86
…lter

Self-review follow-up on the day-start-hour change: extract the
repeated "shift by cutoff" and "day-key -> boundary instant" logic
into shared timeUtils helpers instead of duplicating it across three
timeline modules, and make DayFilterSelect's day options honor the
cutoff too (a pre-cutoff set on the edition's first calendar day can
fold onto the previous day's key, which the filter dropdown needs to
offer).
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 (UTC)
upline Ready Ready Preview Aug 29, 2026 4:17pm

@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 → stagingworkflow run
Last updated: 2026-08-29 16:17:31 UTC

  • ⏭️ DB migrations skipped (no changes)
  • ⏭️ Edge functions 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
Comment on lines 196 to +200
if (!isValid(date)) return null;
const shifted = shiftForDayStart(date, dayStartHour);
const dayFormat = "EEE, MMM d";
if (timezone) return formatInTimeZone(date, timezone, dayFormat);
return format(date, dayFormat);
if (timezone) return formatInTimeZone(shifted, timezone, dayFormat);
return format(shifted, dayFormat);
@github-actions

Copy link
Copy Markdown

Playwright test results

passed  62 passed

Details

stats  62 tests across 20 suites
duration  1 minute, 25 seconds
commit  e2f1d1d

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

Labels

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