From 8428f3a4904f4ebbce2c4a86c51a664657481c27 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 10 Jun 2026 13:29:44 -0600 Subject: [PATCH] Add pagination to admin stops page (50/page) Co-Authored-By: Claude Opus 4.8 --- src/app/admin/stops/page.tsx | 32 ++++++++++- .../admin/stops/StopsDashboardClient.tsx | 56 ++++++++++++++++++- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/app/admin/stops/page.tsx b/src/app/admin/stops/page.tsx index a8e3e50..3c36b1e 100644 --- a/src/app/admin/stops/page.tsx +++ b/src/app/admin/stops/page.tsx @@ -7,6 +7,8 @@ import { redirect } from "next/navigation"; import { pool } from "@/lib/db"; import { type Stop } from "@/components/admin/stops/types"; +const PAGE_SIZE = 50; + const StopIcon = () => ( @@ -14,7 +16,15 @@ const StopIcon = () => ( ); -export default async function AdminStopsPage() { +interface PageProps { + searchParams: Promise<{ page?: string }>; +} + +export default async function AdminStopsPage({ searchParams }: PageProps) { + const params = await searchParams; + const page = Math.max(1, parseInt(params.page ?? "1", 10) || 1); + const offset = (page - 1) * PAGE_SIZE; + const adminUser = await getAdminUser(); if (!adminUser) return ; @@ -24,6 +34,7 @@ export default async function AdminStopsPage() { } let stops: Stop[] = []; + let totalCount = 0; let error: { message: string } | null = null; try { @@ -31,6 +42,13 @@ export default async function AdminStopsPage() { ? `AND brand_id = '${adminUser.brand_id}'` : ""; + // Get total count for pagination + const countResult = await pool.query<{ count: string }>(` + SELECT count(*) as count FROM stops WHERE status = 'active' ${brandFilter} + `); + totalCount = parseInt(countResult.rows[0]?.count ?? "0", 10); + + // Get paginated stops const { rows } = await pool.query(` SELECT s.id, @@ -51,6 +69,7 @@ export default async function AdminStopsPage() { WHERE s.status = 'active' ${brandFilter} ORDER BY s.date ASC + LIMIT ${PAGE_SIZE} OFFSET ${offset} `); stops = rows.map((r) => ({ @@ -73,6 +92,8 @@ export default async function AdminStopsPage() { error = { message: e instanceof Error ? e.message : String(e) }; } + const totalPages = Math.ceil(totalCount / PAGE_SIZE); + if (error) { return (
@@ -81,7 +102,7 @@ export default async function AdminStopsPage() {

Error loading stops @@ -112,7 +133,12 @@ export default async function AdminStopsPage() { {/* Content */}
- +

); diff --git a/src/components/admin/stops/StopsDashboardClient.tsx b/src/components/admin/stops/StopsDashboardClient.tsx index ce29829..9a08c09 100644 --- a/src/components/admin/stops/StopsDashboardClient.tsx +++ b/src/components/admin/stops/StopsDashboardClient.tsx @@ -8,6 +8,9 @@ import StopsList from "./StopsList"; type Props = { stops: Stop[]; + page?: number; + totalPages?: number; + totalCount?: number; }; const TABS: { value: StopView; label: string; hint: string }[] = [ @@ -16,7 +19,7 @@ const TABS: { value: StopView; label: string; hint: string }[] = [ { value: "list", label: "List", hint: "All stops in order" }, ]; -export default function StopsDashboardClient({ stops }: Props) { +export default function StopsDashboardClient({ stops, page = 1, totalPages = 1, totalCount = 0 }: Props) { const [view, setView] = useState("calendar"); const stats = useMemo(() => { @@ -52,7 +55,7 @@ export default function StopsDashboardClient({ stops }: Props) { className="pointer-events-none absolute inset-0 opacity-[0.04]" style={{ backgroundImage: - "url(\"data:image/svg+xml;utf8,\")", + "url(\"data:image/svg+xml;utf8,\")", }} />
@@ -134,6 +137,55 @@ export default function StopsDashboardClient({ stops }: Props) { value={stats.venues} />
+ + {/* Pagination */} + {totalPages > 1 && ( +
+

+ Showing {((page - 1) * 50) + 1}–{Math.min(page * 50, totalCount)} of {totalCount} +

+ +
+ )} {/* Active view */}