import Link from "next/link"; import { notFound } from "next/navigation"; import { PARK_MAP } from "@/lib/parks"; import { openDb, getParkMonthData, getApiId } from "@/lib/db"; import { scrapeRidesForDay } from "@/lib/scrapers/sixflags"; import { fetchLiveRides } from "@/lib/scrapers/queuetimes"; import { QUEUE_TIMES_IDS } from "@/lib/queue-times-map"; import { readParkMeta, getCoasterSet } from "@/lib/park-meta"; import { ParkMonthCalendar } from "@/components/ParkMonthCalendar"; import { LiveRidePanel } from "@/components/LiveRidePanel"; import type { RideStatus, RidesFetchResult } from "@/lib/scrapers/sixflags"; import type { LiveRidesResult } from "@/lib/scrapers/queuetimes"; // used as prop type below import { getTodayLocal, isWithinOperatingWindow } from "@/lib/env"; interface PageProps { params: Promise<{ id: string }>; searchParams: Promise<{ month?: string }>; } function parseMonthParam(param: string | undefined): { year: number; month: number } { if (param && /^\d{4}-\d{2}$/.test(param)) { const [y, m] = param.split("-").map(Number); if (y >= 2020 && y <= 2030 && m >= 1 && m <= 12) { return { year: y, month: m }; } } const [y, m] = getTodayLocal().split("-").map(Number); return { year: y, month: m }; } export default async function ParkPage({ params, searchParams }: PageProps) { const { id } = await params; const { month: monthParam } = await searchParams; const park = PARK_MAP.get(id); if (!park) notFound(); const today = getTodayLocal(); const { year, month } = parseMonthParam(monthParam); const db = openDb(); const monthData = getParkMonthData(db, id, year, month); const apiId = getApiId(db, id); db.close(); const todayData = monthData[today]; const parkOpenToday = todayData?.isOpen && todayData?.hoursLabel; // ── Ride data: try live Queue-Times first, fall back to schedule ────────── const queueTimesId = QUEUE_TIMES_IDS[id]; const parkMeta = readParkMeta(); const coasterSet = getCoasterSet(id, parkMeta); let liveRides: LiveRidesResult | null = null; let ridesResult: RidesFetchResult | null = null; // Determine if we're within the 1h-before-open to 1h-after-close window. const withinWindow = todayData?.hoursLabel ? isWithinOperatingWindow(todayData.hoursLabel, park.timezone) : false; if (queueTimesId) { const raw = await fetchLiveRides(queueTimesId, coasterSet); if (raw) { // Outside the window: show the ride list but force all rides closed liveRides = withinWindow ? raw : { ...raw, rides: raw.rides.map((r) => ({ ...r, isOpen: false, waitMinutes: 0 })), }; } } // Only hit the schedule API as a fallback when live data is unavailable if (!liveRides && apiId !== null) { // Note: the API drops today's date from its response (only returns future dates), // so scrapeRidesForDay may fall back to the nearest upcoming date. ridesResult = await scrapeRidesForDay(apiId, today); } return (
npm run discover
{" "}
to enable ride data.