Adds complete initial codebase for the RJ Bulk Supplies fuel delivery backoffice: - Authentication pages and protected route layouts - Customer, supplier, fuel purchase, and delivery note management - Custom reporting and customer statement sending tools - Full UI component library and Tailwind styling - Server actions, API routes, and PocketBase integration - Development scripts and project configuration updates - Updated README and package metadata
72 lines
2.5 KiB
TypeScript
72 lines
2.5 KiB
TypeScript
import Link from "next/link";
|
||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||
import { Button } from "@/components/ui/button";
|
||
|
||
interface Props {
|
||
/** Current page (1-indexed) */
|
||
page: number;
|
||
/** Total number of pages */
|
||
totalPages: number;
|
||
/** Total record count for "X of Y" */
|
||
totalItems: number;
|
||
/** Page size used */
|
||
perPage: number;
|
||
/** Base path for navigation (e.g. "/customers") */
|
||
basePath: string;
|
||
/** Extra query params to preserve (e.g. { q: "foo" }) */
|
||
query?: Record<string, string | undefined>;
|
||
}
|
||
|
||
function buildHref(basePath: string, page: number, query: Record<string, string | undefined> = {}) {
|
||
const params = new URLSearchParams();
|
||
for (const [k, v] of Object.entries(query)) {
|
||
if (v != null && v !== "") params.set(k, v);
|
||
}
|
||
if (page > 1) params.set("page", String(page));
|
||
const qs = params.toString();
|
||
return qs ? `${basePath}?${qs}` : basePath;
|
||
}
|
||
|
||
export function Pagination({ page, totalPages, totalItems, perPage, basePath, query }: Props) {
|
||
if (totalItems === 0 || totalPages <= 1) return null;
|
||
const from = (page - 1) * perPage + 1;
|
||
const to = Math.min(page * perPage, totalItems);
|
||
const prev = page > 1 ? buildHref(basePath, page - 1, query) : null;
|
||
const next = page < totalPages ? buildHref(basePath, page + 1, query) : null;
|
||
|
||
return (
|
||
<div className="flex flex-wrap items-center justify-between gap-2 px-4 py-3 border-t text-sm">
|
||
<p className="text-muted-foreground">
|
||
Showing <span className="font-medium text-foreground">{from}–{to}</span> of{" "}
|
||
<span className="font-medium text-foreground">{totalItems}</span>
|
||
</p>
|
||
<div className="flex items-center gap-1">
|
||
{prev ? (
|
||
<Button asChild variant="outline" size="sm">
|
||
<Link href={prev}>
|
||
<ChevronLeft className="h-4 w-4" /> Prev
|
||
</Link>
|
||
</Button>
|
||
) : (
|
||
<Button variant="outline" size="sm" disabled>
|
||
<ChevronLeft className="h-4 w-4" /> Prev
|
||
</Button>
|
||
)}
|
||
<span className="px-2 text-muted-foreground">
|
||
Page {page} of {totalPages}
|
||
</span>
|
||
{next ? (
|
||
<Button asChild variant="outline" size="sm">
|
||
<Link href={next}>
|
||
Next <ChevronRight className="h-4 w-4" />
|
||
</Link>
|
||
</Button>
|
||
) : (
|
||
<Button variant="outline" size="sm" disabled>
|
||
Next <ChevronRight className="h-4 w-4" />
|
||
</Button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|