137 lines
2.9 KiB
TypeScript
137 lines
2.9 KiB
TypeScript
"use client";
|
|
import {
|
|
useEffect,
|
|
useState,
|
|
useCallback,
|
|
Ref,
|
|
useImperativeHandle,
|
|
} from "react";
|
|
import SortableTable, { Pagination, SortableTableProps } from "./Table";
|
|
import { PrismaClient } from "@repo/db";
|
|
import { getData } from "./pagiantedTableActions";
|
|
|
|
export interface PaginatedTableRef {
|
|
refresh: () => void;
|
|
}
|
|
|
|
interface PaginatedTableProps<TData>
|
|
extends Omit<SortableTableProps<TData>, "data"> {
|
|
prismaModel: keyof PrismaClient;
|
|
filter?: Record<string, any>;
|
|
rowsPerPage?: number;
|
|
showEditButton?: boolean;
|
|
searchFields?: string[];
|
|
include?: Record<string, boolean>;
|
|
leftOfSearch?: React.ReactNode;
|
|
rightOfSearch?: React.ReactNode;
|
|
leftOfPagination?: React.ReactNode;
|
|
hide?: boolean;
|
|
ref?: Ref<PaginatedTableRef>;
|
|
}
|
|
|
|
export function PaginatedTable<TData>({
|
|
prismaModel,
|
|
rowsPerPage = 10,
|
|
showEditButton = false,
|
|
searchFields = [],
|
|
filter,
|
|
include,
|
|
ref,
|
|
leftOfSearch,
|
|
rightOfSearch,
|
|
leftOfPagination,
|
|
hide,
|
|
...restProps
|
|
}: PaginatedTableProps<TData>) {
|
|
const [data, setData] = useState<TData[]>([]);
|
|
const [page, setPage] = useState(0);
|
|
const [total, setTotal] = useState(0);
|
|
const [searchTerm, setSearchTerm] = useState("");
|
|
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(searchTerm);
|
|
|
|
const RefreshTableData = async () => {
|
|
getData(
|
|
prismaModel,
|
|
rowsPerPage,
|
|
page * rowsPerPage,
|
|
debouncedSearchTerm,
|
|
searchFields,
|
|
filter,
|
|
include,
|
|
).then((result) => {
|
|
if (result) {
|
|
setData(result.data);
|
|
setTotal(result.total);
|
|
}
|
|
});
|
|
};
|
|
|
|
useEffect(() => {
|
|
RefreshTableData();
|
|
}, [filter]);
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
refresh: () => {
|
|
RefreshTableData();
|
|
},
|
|
}));
|
|
|
|
const debounce = (func: Function, delay: number) => {
|
|
let timer: NodeJS.Timeout;
|
|
return (...args: any[]) => {
|
|
clearTimeout(timer);
|
|
timer = setTimeout(() => func(...args), delay);
|
|
};
|
|
};
|
|
|
|
const handleSearchChange = useCallback(
|
|
debounce((value: string) => {
|
|
setDebouncedSearchTerm(value);
|
|
}, 500),
|
|
[],
|
|
);
|
|
|
|
useEffect(() => {
|
|
RefreshTableData();
|
|
}, [page, debouncedSearchTerm]);
|
|
|
|
return (
|
|
<div className="space-y-4 m-4">
|
|
<div className="flex items-center gap-2">
|
|
<div className="flex-1">{leftOfSearch}</div>
|
|
{searchFields.length > 0 && (
|
|
<input
|
|
type="text"
|
|
placeholder="Suchen..."
|
|
value={searchTerm}
|
|
onChange={(e) => {
|
|
setSearchTerm(e.target.value);
|
|
handleSearchChange(e.target.value);
|
|
}}
|
|
className="input input-bordered w-full max-w-xs justify-end"
|
|
/>
|
|
)}
|
|
<div className="flex justify-center">{rightOfSearch}</div>
|
|
</div>
|
|
{!hide && (
|
|
<SortableTable
|
|
data={data}
|
|
prismaModel={prismaModel}
|
|
showEditButton={showEditButton}
|
|
{...restProps}
|
|
/>
|
|
)}
|
|
<div className="flex items-between">
|
|
{leftOfPagination}
|
|
{!hide && (
|
|
<Pagination
|
|
totalPages={Math.ceil(total / rowsPerPage)}
|
|
page={page}
|
|
setPage={setPage}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|