Files
var-monorepo/apps/hub/app/_components/Table.tsx
2025-02-16 17:53:55 +01:00

139 lines
3.6 KiB
TypeScript

'use client';
import { useState } from 'react';
import {
useReactTable,
getCoreRowModel,
getSortedRowModel,
ColumnDef,
SortingState,
flexRender,
} from '@tanstack/react-table';
import { ArrowLeft, ArrowRight, ChevronDown, ChevronUp } from 'lucide-react'; // Icons for sorting
import Link from 'next/link';
import { PrismaClient } from '@repo/db';
export interface SortableTableProps<TData> {
data: TData[];
columns: ColumnDef<TData>[];
showEditButton?: boolean;
prismaModel?: keyof PrismaClient;
}
export default function SortableTable<TData>({
data,
columns,
prismaModel,
showEditButton,
}: SortableTableProps<TData>) {
const [sorting, setSorting] = useState<SortingState>([]);
const table = useReactTable({
data,
columns: showEditButton
? [
...columns,
{
header: 'Actions',
cell: ({ row }) => (
<div className="flex items-center gap-1">
<Link
href={`/admin/${prismaModel as string}/${(row.original as any).id}`}
>
<button className="btn btn-sm">Edit</button>
</Link>
</div>
),
},
]
: columns,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
onSortingChange: setSorting,
state: { sorting },
});
return (
<div className="overflow-x-auto">
<table className="table table-zebra w-full">
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th
key={header.id}
onClick={header.column.getToggleSortingHandler()}
>
<div className="flex items-center gap-1 cursor-pointer">
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
{header.column.getIsSorted() === 'asc' && (
<ChevronUp size={16} />
)}
{header.column.getIsSorted() === 'desc' && (
<ChevronDown size={16} />
)}
</div>
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => (
<td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
}
export const Pagination = ({
page,
totalPages,
setPage,
}: {
page: number;
totalPages: number;
setPage: (page: number) => void;
}) => {
if (totalPages === 0) return null;
return (
<div className="join w-full justify-end">
<button
className="join-item btn"
disabled={page === 0}
onClick={() => setPage(page - 1)}
>
<ArrowLeft size={16} />
</button>
<select
className="select join-item"
value={page}
onChange={(e) => setPage(Number(e.target.value))}
>
{Array.from({ length: totalPages }).map((_, i) => (
<option key={i} value={i}>
{i + 1}
</option>
))}
</select>
<button
className="join-item btn"
disabled={page === totalPages - 1}
onClick={() => page < totalPages && setPage(page + 1)}
>
<ArrowRight size={16} />
</button>
</div>
);
};