Lade-anzeige für Tabellen

This commit is contained in:
PxlLoewe
2025-07-11 23:23:30 -07:00
parent bd40c9f817
commit d2b287abdc
2 changed files with 67 additions and 16 deletions

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useState, Ref, useImperativeHandle } from "react"; import { useState, Ref, useImperativeHandle, useEffect, useCallback } from "react";
import SortableTable, { Pagination, SortableTableProps } from "./Table"; import SortableTable, { Pagination, RowsPerPage, SortableTableProps } from "./Table";
import { PrismaClient } from "@repo/db"; import { PrismaClient } from "@repo/db";
import { getData } from "./pagiantedTableActions"; import { getData } from "./pagiantedTableActions";
import { useDebounce } from "@repo/shared-components"; import { useDebounce } from "@repo/shared-components";
@@ -12,7 +12,7 @@ export interface PaginatedTableRef {
interface PaginatedTableProps<TData> extends Omit<SortableTableProps<TData>, "data"> { interface PaginatedTableProps<TData> extends Omit<SortableTableProps<TData>, "data"> {
prismaModel: keyof PrismaClient; prismaModel: keyof PrismaClient;
filter?: Record<string, unknown>; filter?: Record<string, unknown>;
rowsPerPage?: number; initialRowsPerPage?: number;
searchFields?: string[]; searchFields?: string[];
include?: Record<string, boolean>; include?: Record<string, boolean>;
strictQuery?: boolean; strictQuery?: boolean;
@@ -25,7 +25,7 @@ interface PaginatedTableProps<TData> extends Omit<SortableTableProps<TData>, "da
export function PaginatedTable<TData>({ export function PaginatedTable<TData>({
prismaModel, prismaModel,
rowsPerPage = 10, initialRowsPerPage = 30,
searchFields = [], searchFields = [],
filter, filter,
include, include,
@@ -38,6 +38,7 @@ export function PaginatedTable<TData>({
...restProps ...restProps
}: PaginatedTableProps<TData>) { }: PaginatedTableProps<TData>) {
const [data, setData] = useState<TData[]>([]); const [data, setData] = useState<TData[]>([]);
const [rowsPerPage, setRowsPerPage] = useState(initialRowsPerPage);
const [page, setPage] = useState(0); const [page, setPage] = useState(0);
const [total, setTotal] = useState(0); const [total, setTotal] = useState(0);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
@@ -52,8 +53,10 @@ export function PaginatedTable<TData>({
) )
: {}, : {},
); );
const [loading, setLoading] = useState(false);
const RefreshTableData = async () => { const refreshTableData = useCallback(async () => {
setLoading(true);
getData( getData(
prismaModel, prismaModel,
rowsPerPage, rowsPerPage,
@@ -75,23 +78,43 @@ export function PaginatedTable<TData>({
return acc; return acc;
}, {}) }, {})
: undefined, : undefined,
).then((result) => { )
.then((result) => {
if (result) { if (result) {
setData(result.data); setData(result.data);
setTotal(result.total); setTotal(result.total);
} }
})
.finally(() => {
setLoading(false);
}); });
}; }, [
prismaModel,
rowsPerPage,
page,
searchTerm,
searchFields,
filter,
include,
orderBy,
strictQuery,
restProps.columns,
]);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
refresh: () => { refresh: () => {
RefreshTableData(); refreshTableData();
}, },
})); }));
// useEffect to show loading spinner
useEffect(() => {
setLoading(true);
}, [searchTerm, page, rowsPerPage, orderBy, filter, setLoading, refreshTableData]);
useDebounce( useDebounce(
() => { () => {
RefreshTableData(); refreshTableData();
}, },
500, 500,
[searchTerm, page, rowsPerPage, orderBy, filter], [searchTerm, page, rowsPerPage, orderBy, filter],
@@ -100,7 +123,10 @@ export function PaginatedTable<TData>({
return ( return (
<div className="space-y-4 m-4"> <div className="space-y-4 m-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="flex-1">{leftOfSearch}</div> <div className="flex-1 flex gap-2">
<div>{leftOfSearch}</div>
<div>{loading && <span className="loading loading-dots loading-md" />}</div>
</div>
{searchFields.length > 0 && ( {searchFields.length > 0 && (
<input <input
type="text" type="text"
@@ -126,7 +152,10 @@ export function PaginatedTable<TData>({
<div className="flex items-between"> <div className="flex items-between">
{leftOfPagination} {leftOfPagination}
{!hide && ( {!hide && (
<>
<RowsPerPage rowsPerPage={rowsPerPage} setRowsPerPage={setRowsPerPage} />
<Pagination totalPages={Math.ceil(total / rowsPerPage)} page={page} setPage={setPage} /> <Pagination totalPages={Math.ceil(total / rowsPerPage)} page={page} setPage={setPage} />
</>
)} )}
</div> </div>
</div> </div>

View File

@@ -86,6 +86,28 @@ export default function SortableTable<TData>({
); );
} }
export const RowsPerPage = ({
rowsPerPage,
setRowsPerPage,
}: {
rowsPerPage: number;
setRowsPerPage: (rowsPerPage: number) => void;
}) => {
return (
<select
className="select w-32"
value={rowsPerPage}
onChange={(e) => setRowsPerPage(Number(e.target.value))}
>
<option value={10}>10</option>
<option value={30}>30</option>
<option value={50}>50</option>
<option value={100}>100</option>
<option value={300}>300</option>
</select>
);
};
export const Pagination = ({ export const Pagination = ({
page, page,
totalPages, totalPages,