diff --git a/apps/hub/app/(app)/admin/station/page.tsx b/apps/hub/app/(app)/admin/station/page.tsx index 70c3c91c..e525ebf6 100644 --- a/apps/hub/app/(app)/admin/station/page.tsx +++ b/apps/hub/app/(app)/admin/station/page.tsx @@ -1,6 +1,6 @@ -import { DatabaseBackupIcon } from 'lucide-react'; -import { PaginatedTable } from '../../../_components/PaginatedTable'; -import Link from 'next/link'; +import { DatabaseBackupIcon } from "lucide-react"; +import { PaginatedTable } from "../../../_components/PaginatedTable"; +import Link from "next/link"; export default () => { return ( @@ -9,7 +9,7 @@ export default () => { Stationen - + @@ -18,22 +18,23 @@ export default () => { diff --git a/apps/hub/app/(app)/admin/user/page.tsx b/apps/hub/app/(app)/admin/user/page.tsx index d386dff1..02ee1736 100644 --- a/apps/hub/app/(app)/admin/user/page.tsx +++ b/apps/hub/app/(app)/admin/user/page.tsx @@ -1,5 +1,5 @@ -import { User2 } from 'lucide-react'; -import { PaginatedTable } from '../../../_components/PaginatedTable'; +import { User2 } from "lucide-react"; +import { PaginatedTable } from "../../../_components/PaginatedTable"; export default async () => { return ( @@ -10,22 +10,23 @@ export default async () => { diff --git a/apps/hub/app/_components/PaginatedTable.tsx b/apps/hub/app/_components/PaginatedTable.tsx index 9b23ec4b..4e509f62 100644 --- a/apps/hub/app/_components/PaginatedTable.tsx +++ b/apps/hub/app/_components/PaginatedTable.tsx @@ -1,37 +1,76 @@ -'use client'; -import { useEffect, useState } from 'react'; -import SortableTable, { Pagination, SortableTableProps } from './Table'; -import { PrismaClient } from '@repo/db'; -import { getData } from './pagiantedTableActions'; +"use client"; +import { useEffect, useState, useCallback } from "react"; +import SortableTable, { Pagination, SortableTableProps } from "./Table"; +import { PrismaClient } from "@repo/db"; +import { getData } from "./pagiantedTableActions"; interface PaginatedTableProps - extends Omit, 'data'> { + extends Omit, "data"> { prismaModel: keyof PrismaClient; rowsPerPage?: number; showEditButton?: boolean; + searchFields: string[]; } export function PaginatedTable({ prismaModel, rowsPerPage = 10, showEditButton = false, + searchFields, ...restProps }: PaginatedTableProps) { const [data, setData] = useState([]); const [page, setPage] = useState(0); const [total, setTotal] = useState(0); + const [searchTerm, setSearchTerm] = useState(""); + const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(searchTerm); + + 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(() => { - getData(prismaModel, rowsPerPage, page * rowsPerPage).then((result) => { + getData( + prismaModel, + rowsPerPage, + page * rowsPerPage, + debouncedSearchTerm, + searchFields + ).then((result) => { if (result) { setData(result.data); setTotal(result.total); } }); - }, [page]); + }, [page, debouncedSearchTerm]); return ( -
+
+ {searchFields.length > 0 && ( +
+ { + setSearchTerm(e.target.value); + handleSearchChange(e.target.value); + }} + className="input input-bordered w-full max-w-xs justify-end" + /> +
+ )} { - const prisma = new PrismaClient(); - if ( - !prismaModelName || - !prisma[prismaModelName] || - !('findMany' in prisma[prismaModelName]) - ) - return; - const model = prisma[prismaModelName] as any; - if (!model.findMany || !model.count) return; - const data = await model.findMany({ - take, - skip, +const prisma = new PrismaClient(); + +export async function getData( + model: keyof PrismaClient, + limit: number, + offset: number, + searchTerm: string, + searchFields: string[] +) { + if (!model || !prisma[model]) { + return { data: [], total: 0 }; + } + + const formattedId = searchTerm.match(/^VAR(\d+)$/)?.[1]; + + const where = searchTerm + ? { + OR: [ + formattedId ? { id: formattedId } : undefined, + ...searchFields.map((field) => ({ + [field]: { contains: searchTerm }, + })), + ].filter(Boolean), + } + : {}; + + if (!prisma[model]) { + return { data: [], total: 0 }; + } + + const data = await (prisma[model] as any).findMany({ + where, + take: limit, + skip: offset, }); - const total = await model.count(); + + const total = await (prisma[model] as any).count({ where }); + return { data, total }; -}; +}