fix: render today's wait chart in viewer's local time + close stale live state
Build and Deploy / Build & Push (push) Successful in 1m8s
Build and Deploy / Build & Push (push) Successful in 1m8s
Two related polish fixes for the ride detail page: 1. Wait-time chart x-axis now uses Intl.DateTimeFormat with no timezone argument, so an Eastern-time user viewing a Pacific park sees ET on the axis. Backend now sends recorded_at (UTC) alongside local_time. 2. Ride-history endpoint now applies the same operating-window gate the /rides route uses. Queue-Times keeps reporting yesterday's last wait with isOpen=true overnight, which made the "Right now" pill show a live wait time when the park was actually closed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -278,6 +278,7 @@ export function listRidesForPark(parkId: string): RideRow[] {
|
||||
}
|
||||
|
||||
export interface DailySample {
|
||||
recordedAt: string;
|
||||
localTime: string;
|
||||
isOpen: boolean;
|
||||
waitMinutes: number | null;
|
||||
@@ -291,18 +292,20 @@ export function getRideSamplesForDay(
|
||||
): DailySample[] {
|
||||
const rows = getDb()
|
||||
.prepare(
|
||||
`SELECT local_time, is_open, wait_minutes, fast_lane_minutes
|
||||
`SELECT recorded_at, local_time, is_open, wait_minutes, fast_lane_minutes
|
||||
FROM ride_wait_samples
|
||||
WHERE park_id = ? AND qt_ride_id = ? AND local_date = ?
|
||||
ORDER BY local_time`,
|
||||
ORDER BY recorded_at`,
|
||||
)
|
||||
.all(parkId, qtRideId, localDate) as {
|
||||
recorded_at: string;
|
||||
local_time: string;
|
||||
is_open: number;
|
||||
wait_minutes: number | null;
|
||||
fast_lane_minutes: number | null;
|
||||
}[];
|
||||
return rows.map((r) => ({
|
||||
recordedAt: r.recorded_at,
|
||||
localTime: r.local_time,
|
||||
isOpen: r.is_open === 1,
|
||||
waitMinutes: r.wait_minutes,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { PARK_MAP } from "../../../lib/parks";
|
||||
import {
|
||||
getDayData,
|
||||
getRideBySlug,
|
||||
getRideSamplesForDay,
|
||||
getRideDailyAggregates,
|
||||
@@ -22,6 +23,7 @@ import {
|
||||
import { liveRidesCache, fastLaneCache } from "../services/live-cache";
|
||||
import { slugifyRideName } from "../../../lib/ride-slug";
|
||||
import { lookupFastLane } from "../../../lib/scrapers/sixflags-waittimes";
|
||||
import { getTodayLocal, isWithinOperatingWindow } from "../../../lib/env";
|
||||
|
||||
const app = new Hono();
|
||||
|
||||
@@ -72,6 +74,15 @@ app.get("/:parkId/rides/:slug", (c) => {
|
||||
const fastLaneCacheEntry = fastLaneCache.get(parkId);
|
||||
const flMatch = liveMatch && fastLaneCacheEntry ? lookupFastLane(liveMatch.name, fastLaneCacheEntry) : null;
|
||||
|
||||
// Operating-window gate. Queue-Times keeps reporting yesterday's last wait
|
||||
// with isOpen=true overnight, so we override to closed when we're outside
|
||||
// the park's hours — same behaviour as the /rides route.
|
||||
const todayData = getDayData(parkId, getTodayLocal());
|
||||
const withinWindow = todayData?.hoursLabel
|
||||
? isWithinOperatingWindow(todayData.hoursLabel, park.timezone)
|
||||
: false;
|
||||
const liveIsOpen = Boolean(liveMatch?.isOpen) && withinWindow;
|
||||
|
||||
c.header("Cache-Control", "public, max-age=60, stale-while-revalidate=120");
|
||||
return c.json({
|
||||
park: {
|
||||
@@ -91,10 +102,10 @@ app.get("/:parkId/rides/:slug", (c) => {
|
||||
},
|
||||
live: liveMatch
|
||||
? {
|
||||
isOpen: liveMatch.isOpen,
|
||||
waitMinutes: liveMatch.waitMinutes,
|
||||
isOpen: liveIsOpen,
|
||||
waitMinutes: liveIsOpen ? liveMatch.waitMinutes : 0,
|
||||
hasFastLane: Boolean(flMatch?.hasFastLane),
|
||||
fastLaneMinutes: liveMatch.isOpen ? (flMatch?.fastLaneMinutes ?? null) : null,
|
||||
fastLaneMinutes: liveIsOpen ? (flMatch?.fastLaneMinutes ?? null) : null,
|
||||
lastUpdated: liveMatch.lastUpdated,
|
||||
}
|
||||
: null,
|
||||
|
||||
Reference in New Issue
Block a user