Files
var-monorepo/apps/hub/app/_components/PaginatedTable.tsx

123 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;
ref?: Ref<PaginatedTableRef>;
}
export function PaginatedTable<TData>({
prismaModel,
rowsPerPage = 10,
showEditButton = false,
searchFields = [],
filter,
include,
ref,
leftOfSearch,
rightOfSearch,
...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);
}
});
};
useImperativeHandle(ref, () => ({
refresh: () => {
console.log('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>
<SortableTable
data={data}
prismaModel={prismaModel}
showEditButton={showEditButton}
{...restProps}
/>
<Pagination
totalPages={Math.ceil(total / rowsPerPage)}
page={page}
setPage={setPage}
/>
</div>
);
}