feat: amber indicator during post-close wind-down buffer
All checks were successful
Build and Deploy / Build & Push (push) Successful in 2m22s

Parks in the 1-hour buffer after scheduled close now show amber instead
of green: the dot on the desktop calendar turns yellow, and the mobile
card badge changes from "Open today" (green) to "Closing" (amber).

- getOperatingStatus() replaces isWithinOperatingWindow's inline logic,
  returning "open" | "closing" | "closed"; isWithinOperatingWindow now
  delegates to it so all callers are unchanged
- closingParkIds[] is computed server-side and threaded through
  HomePageClient → WeekCalendar/MobileCardList → ParkRow/ParkCard
- New --color-closing-* CSS variables mirror the green palette in amber

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Josh Wright
2026-04-05 09:06:45 -04:00
parent 090f4d876d
commit 53297a7cff
7 changed files with 57 additions and 14 deletions

View File

@@ -12,6 +12,7 @@ interface WeekCalendarProps {
grouped?: Map<Region, Park[]>; // pre-grouped parks (if provided, renders region headers)
rideCounts?: Record<string, number>; // parkId → open ride/coaster count for today
coastersOnly?: boolean;
closingParkIds?: string[]; // parks in the post-close wind-down buffer
}
const DOW = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
@@ -188,6 +189,7 @@ function ParkRow({
parkData,
rideCounts,
coastersOnly,
closingParkIds,
}: {
park: Park;
parkIdx: number;
@@ -196,9 +198,11 @@ function ParkRow({
parkData: Record<string, DayData>;
rideCounts?: Record<string, number>;
coastersOnly?: boolean;
closingParkIds?: string[];
}) {
const rowBg = parkIdx % 2 === 0 ? "var(--color-bg)" : "var(--color-surface)";
const tzAbbr = getTimezoneAbbr(park.timezone);
const isClosing = closingParkIds?.includes(park.id) ?? false;
return (
<tr
className="park-row"
@@ -234,9 +238,11 @@ function ParkRow({
width: 7,
height: 7,
borderRadius: "50%",
background: "var(--color-open-text)",
background: isClosing ? "var(--color-closing-text)" : "var(--color-open-text)",
flexShrink: 0,
boxShadow: "0 0 5px var(--color-open-text)",
boxShadow: isClosing
? "0 0 5px var(--color-closing-text)"
: "0 0 5px var(--color-open-text)",
}} />
)}
</div>
@@ -245,7 +251,7 @@ function ParkRow({
</div>
</div>
{rideCounts?.[park.id] !== undefined && (
<div style={{ fontSize: "0.72rem", color: "var(--color-open-hours)", fontWeight: 600, whiteSpace: "nowrap", flexShrink: 0 }}>
<div style={{ fontSize: "0.72rem", color: isClosing ? "var(--color-closing-hours)" : "var(--color-open-hours)", fontWeight: 600, whiteSpace: "nowrap", flexShrink: 0 }}>
{rideCounts[park.id]} {coastersOnly
? (rideCounts[park.id] === 1 ? "coaster" : "coasters")
: (rideCounts[park.id] === 1 ? "ride" : "rides")} operating
@@ -266,7 +272,7 @@ function ParkRow({
);
}
export function WeekCalendar({ parks, weekDates, data, grouped, rideCounts, coastersOnly }: WeekCalendarProps) {
export function WeekCalendar({ parks, weekDates, data, grouped, rideCounts, coastersOnly, closingParkIds }: WeekCalendarProps) {
const today = getTodayLocal();
const parsedDates = weekDates.map(parseDate);
@@ -382,6 +388,7 @@ export function WeekCalendar({ parks, weekDates, data, grouped, rideCounts, coas
parkData={data[park.id] ?? {}}
rideCounts={rideCounts}
coastersOnly={coastersOnly}
closingParkIds={closingParkIds}
/>
))}
</Fragment>