feat: add pagination support to DataTable component

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
fuomag9
2026-02-27 17:53:23 +01:00
parent 28f9fc1d8a
commit 89c5d4b838

View File

@@ -1,76 +1,113 @@
"use client";
import {
Card,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
Box
Box,
Card,
Pagination,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
} from "@mui/material";
import { ReactNode } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
type Column<T> = {
id: string;
label: string;
align?: "left" | "right" | "center";
width?: string | number;
render?: (row: T) => ReactNode;
export type Column<T> = {
id: string;
label: string;
align?: "left" | "right" | "center";
width?: string | number;
render?: (row: T) => ReactNode;
};
type DataTableProps<T> = {
columns: Column<T>[];
data: T[];
keyField: keyof T;
emptyMessage?: string;
loading?: boolean;
columns: Column<T>[];
data: T[];
keyField: keyof T;
emptyMessage?: string;
loading?: boolean;
pagination?: {
total: number;
page: number;
perPage: number;
};
};
export function DataTable<T>({
columns,
data,
keyField,
emptyMessage = "No data available",
loading = false
columns,
data,
keyField,
emptyMessage = "No data available",
loading = false,
pagination,
}: DataTableProps<T>) {
return (
<TableContainer component={Card} variant="outlined">
<Table>
<TableHead>
<TableRow>
{columns.map((col) => (
<TableCell
key={col.id}
align={col.align || "left"}
width={col.width}
>
{col.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{data.length === 0 && !loading ? (
<TableRow>
<TableCell colSpan={columns.length} align="center" sx={{ py: 8 }}>
<Typography color="text.secondary">{emptyMessage}</Typography>
</TableCell>
</TableRow>
) : (
data.map((row) => (
<TableRow key={String(row[keyField])}>
{columns.map((col) => (
<TableCell key={col.id} align={col.align || "left"}>
{col.render ? col.render(row) : (row as any)[col.id]}
</TableCell>
))}
</TableRow>
))
)}
</TableBody>
</Table>
</TableContainer>
);
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const pageCount = pagination
? Math.ceil(pagination.total / pagination.perPage)
: 0;
function handlePageChange(_: React.ChangeEvent<unknown>, page: number) {
const params = new URLSearchParams(searchParams.toString());
params.set("page", String(page));
router.push(`${pathname}?${params.toString()}`);
}
return (
<Box>
<TableContainer component={Card} variant="outlined">
<Table>
<TableHead>
<TableRow>
{columns.map((col) => (
<TableCell
key={col.id}
align={col.align || "left"}
width={col.width}
>
{col.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{data.length === 0 && !loading ? (
<TableRow>
<TableCell colSpan={columns.length} align="center" sx={{ py: 8 }}>
<Typography color="text.secondary">{emptyMessage}</Typography>
</TableCell>
</TableRow>
) : (
data.map((row) => (
<TableRow key={String(row[keyField])}>
{columns.map((col) => (
<TableCell key={col.id} align={col.align || "left"}>
{col.render ? col.render(row) : (row as Record<string, unknown>)[col.id] as ReactNode}
</TableCell>
))}
</TableRow>
))
)}
</TableBody>
</Table>
</TableContainer>
{pagination && pageCount > 1 && (
<Box sx={{ display: "flex", justifyContent: "center", mt: 2 }}>
<Pagination
count={pageCount}
page={pagination.page}
onChange={handlePageChange}
color="primary"
shape="rounded"
/>
</Box>
)}
</Box>
);
}