All checks were successful
Build and Deploy / Build & Push (push) Successful in 53s
- Moves the coaster toggle out of WeekNav and into the homepage header top-right as "🎢 Coaster Mode", alongside the parks open badge - State is stored in localStorage ("coasterMode") so the preference persists across sessions and page refreshes - Dropped the ?coasters=1 URL param entirely; the server always fetches both rideCounts and coasterCounts, and HomePageClient picks which to display client-side — no flash or server round-trip on toggle - Individual park pages: LiveRidePanel reads localStorage on mount and pre-selects the Coasters Only filter when Coaster Mode is active - Extracted HomePageClient (client component) to own the full homepage UI; page.tsx is now pure data-fetching Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
102 lines
3.5 KiB
TypeScript
102 lines
3.5 KiB
TypeScript
import { HomePageClient } from "@/components/HomePageClient";
|
|
import { PARKS } from "@/lib/parks";
|
|
import { openDb, getDateRange } from "@/lib/db";
|
|
import { getTodayLocal, isWithinOperatingWindow } from "@/lib/env";
|
|
import { fetchLiveRides } from "@/lib/scrapers/queuetimes";
|
|
import { QUEUE_TIMES_IDS } from "@/lib/queue-times-map";
|
|
import { readParkMeta, getCoasterSet } from "@/lib/park-meta";
|
|
|
|
interface PageProps {
|
|
searchParams: Promise<{ week?: string }>;
|
|
}
|
|
|
|
function getWeekStart(param: string | undefined): string {
|
|
if (param && /^\d{4}-\d{2}-\d{2}$/.test(param)) {
|
|
const d = new Date(param + "T00:00:00");
|
|
if (!isNaN(d.getTime())) {
|
|
d.setDate(d.getDate() - d.getDay());
|
|
return d.toISOString().slice(0, 10);
|
|
}
|
|
}
|
|
const todayIso = getTodayLocal();
|
|
const d = new Date(todayIso + "T00:00:00");
|
|
d.setDate(d.getDate() - d.getDay());
|
|
return d.toISOString().slice(0, 10);
|
|
}
|
|
|
|
function getWeekDates(sundayIso: string): string[] {
|
|
return Array.from({ length: 7 }, (_, i) => {
|
|
const d = new Date(sundayIso + "T00:00:00");
|
|
d.setDate(d.getDate() + i);
|
|
return d.toISOString().slice(0, 10);
|
|
});
|
|
}
|
|
|
|
function getCurrentWeekStart(): string {
|
|
const todayIso = getTodayLocal();
|
|
const d = new Date(todayIso + "T00:00:00");
|
|
d.setDate(d.getDate() - d.getDay());
|
|
return d.toISOString().slice(0, 10);
|
|
}
|
|
|
|
export default async function HomePage({ searchParams }: PageProps) {
|
|
const params = await searchParams;
|
|
const weekStart = getWeekStart(params.week);
|
|
const weekDates = getWeekDates(weekStart);
|
|
const endDate = weekDates[6];
|
|
const today = getTodayLocal();
|
|
const isCurrentWeek = weekStart === getCurrentWeekStart();
|
|
|
|
const db = openDb();
|
|
const data = getDateRange(db, weekStart, endDate);
|
|
db.close();
|
|
|
|
const scrapedCount = Object.values(data).reduce(
|
|
(sum, parkData) => sum + Object.keys(parkData).length,
|
|
0
|
|
);
|
|
|
|
// Always fetch both ride and coaster counts — the client decides which to display.
|
|
const parkMeta = readParkMeta();
|
|
const hasCoasterData = PARKS.some((p) => (parkMeta[p.id]?.coasters.length ?? 0) > 0);
|
|
|
|
let rideCounts: Record<string, number> = {};
|
|
let coasterCounts: Record<string, number> = {};
|
|
if (weekDates.includes(today)) {
|
|
const openTodayParks = PARKS.filter((p) => {
|
|
const dayData = data[p.id]?.[today];
|
|
if (!dayData?.isOpen || !QUEUE_TIMES_IDS[p.id] || !dayData.hoursLabel) return false;
|
|
return isWithinOperatingWindow(dayData.hoursLabel, p.timezone);
|
|
});
|
|
const results = await Promise.all(
|
|
openTodayParks.map(async (p) => {
|
|
const coasterSet = getCoasterSet(p.id, parkMeta);
|
|
const result = await fetchLiveRides(QUEUE_TIMES_IDS[p.id], coasterSet, 300);
|
|
const rideCount = result ? result.rides.filter((r) => r.isOpen).length : 0;
|
|
const coasterCount = result ? result.rides.filter((r) => r.isOpen && r.isCoaster).length : 0;
|
|
return { id: p.id, rideCount, coasterCount };
|
|
})
|
|
);
|
|
rideCounts = Object.fromEntries(
|
|
results.filter(({ rideCount }) => rideCount > 0).map(({ id, rideCount }) => [id, rideCount])
|
|
);
|
|
coasterCounts = Object.fromEntries(
|
|
results.filter(({ coasterCount }) => coasterCount > 0).map(({ id, coasterCount }) => [id, coasterCount])
|
|
);
|
|
}
|
|
|
|
return (
|
|
<HomePageClient
|
|
weekStart={weekStart}
|
|
weekDates={weekDates}
|
|
today={today}
|
|
isCurrentWeek={isCurrentWeek}
|
|
data={data}
|
|
rideCounts={rideCounts}
|
|
coasterCounts={coasterCounts}
|
|
hasCoasterData={hasCoasterData}
|
|
scrapedCount={scrapedCount}
|
|
/>
|
|
);
|
|
}
|