Add pagination to admin stops page (50/page)
Deploy to route.crispygoat.com / deploy (push) Successful in 4m37s

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tyler
2026-06-10 13:29:44 -06:00
parent 77fb8fe7ee
commit 8428f3a490
2 changed files with 83 additions and 5 deletions
@@ -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<StopView>("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,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/><feColorMatrix values='0 0 0 0 0.2 0 0 0 0 0.2 0 0 0 0 0.1 0 0 0 0.6 0'/></filter><rect width='120' height='120' filter='url(%23n)'/></svg>\")",
"url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/><feColorMatrix values='0 0 0 0 0.2 0 0 0 0 0.2 0 0 0 0 0.1 0 0 0 0 0.6 0'/></filter><rect width='120' height='120' filter='url(%23n)'/></svg>\")",
}}
/>
<div className="relative flex flex-col gap-5 lg:flex-row lg:items-end lg:justify-between">
@@ -134,6 +137,55 @@ export default function StopsDashboardClient({ stops }: Props) {
value={stats.venues}
/>
</div>
{/* Pagination */}
{totalPages > 1 && (
<div className="relative flex items-center justify-between border-t border-[var(--admin-border-light)] pt-4 mt-4">
<p className="font-mono text-xs text-[var(--admin-text-muted)]">
Showing {((page - 1) * 50) + 1}{Math.min(page * 50, totalCount)} of {totalCount}
</p>
<div className="flex items-center gap-1">
<a
href={page > 1 ? `?page=${page - 1}` : "#"}
aria-disabled={page <= 1}
className={`inline-flex h-8 w-8 items-center justify-center rounded-md text-sm font-medium transition-colors ${
page <= 1
? "text-[var(--admin-text-muted)] cursor-not-allowed pointer-events-none"
: "text-[var(--admin-text-secondary)] hover:bg-[var(--admin-bg-subtle)]"
}`}
>
</a>
{Array.from({ length: Math.min(totalPages, 7) }, (_, i) => {
const p = i + 1;
return (
<a
key={p}
href={`?page=${p}`}
className={`inline-flex h-8 w-8 items-center justify-center rounded-md text-sm font-medium transition-colors ${
p === page
? "bg-[var(--admin-accent-light)] text-[var(--admin-accent-text)]"
: "text-[var(--admin-text-secondary)] hover:bg-[var(--admin-bg-subtle)]"
}`}
>
{p}
</a>
);
})}
<a
href={page < totalPages ? `?page=${page + 1}` : "#"}
aria-disabled={page >= totalPages}
className={`inline-flex h-8 w-8 items-center justify-center rounded-md text-sm font-medium transition-colors ${
page >= totalPages
? "text-[var(--admin-text-muted)] cursor-not-allowed pointer-events-none"
: "text-[var(--admin-text-secondary)] hover:bg-[var(--admin-bg-subtle)]"
}`}
>
</a>
</div>
</div>
)}
</section>
{/* Active view */}