completed paginated Component
This commit is contained in:
@@ -1,27 +1,41 @@
|
|||||||
import SortableTable, { SortableTableProps } from './Table';
|
'use client';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import SortableTable, { Pagination, SortableTableProps } from './Table';
|
||||||
|
import { PrismaClient } from '@repo/db';
|
||||||
|
import { getData } from './pagiantedTableActions';
|
||||||
|
|
||||||
interface PaginatedTableProps<TData>
|
interface PaginatedTableProps<TData>
|
||||||
extends Omit<SortableTableProps<TData>, 'data'> {
|
extends Omit<SortableTableProps<TData>, 'data'> {
|
||||||
prismaGetter: (
|
prismaModel: keyof PrismaClient;
|
||||||
fnProps: {
|
rowsPerPage?: number;
|
||||||
cursor: number;
|
|
||||||
take: number;
|
|
||||||
} & any
|
|
||||||
) => Promise<any>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function PaginatedTable<TData>({
|
export function PaginatedTable<TData>({
|
||||||
prismaGetter,
|
prismaModel,
|
||||||
|
rowsPerPage = 10,
|
||||||
...restProps
|
...restProps
|
||||||
}: PaginatedTableProps<TData>) {
|
}: PaginatedTableProps<TData>) {
|
||||||
const data = await prismaGetter({
|
const [data, setData] = useState<TData[]>([]);
|
||||||
cursor: 0,
|
const [page, setPage] = useState(0);
|
||||||
take: 10,
|
const [total, setTotal] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getData(prismaModel, rowsPerPage, page * rowsPerPage).then((result) => {
|
||||||
|
if (result) {
|
||||||
|
setData(result.data);
|
||||||
|
setTotal(result.total);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}, [page]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="space-y-4">
|
||||||
<SortableTable data={data} {...restProps} />
|
<SortableTable data={data} {...restProps} />
|
||||||
|
<Pagination
|
||||||
|
totalPages={Math.ceil(total / rowsPerPage)}
|
||||||
|
page={page}
|
||||||
|
setPage={setPage}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
SortingState,
|
SortingState,
|
||||||
flexRender,
|
flexRender,
|
||||||
} from '@tanstack/react-table';
|
} from '@tanstack/react-table';
|
||||||
import { ChevronDown, ChevronUp } from 'lucide-react'; // Icons for sorting
|
import { ArrowLeft, ArrowRight, ChevronDown, ChevronUp } from 'lucide-react'; // Icons for sorting
|
||||||
|
|
||||||
export interface SortableTableProps<TData> {
|
export interface SortableTableProps<TData> {
|
||||||
data: TData[];
|
data: TData[];
|
||||||
@@ -73,3 +73,44 @@ export default function SortableTable<TData>({
|
|||||||
</div>
|
</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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
24
apps/hub/app/_components/pagiantedTableActions.ts
Normal file
24
apps/hub/app/_components/pagiantedTableActions.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use server';
|
||||||
|
import { PrismaClient } from '@repo/db';
|
||||||
|
|
||||||
|
export const getData = async (
|
||||||
|
prismaModelName: keyof PrismaClient,
|
||||||
|
take: number,
|
||||||
|
skip: number
|
||||||
|
) => {
|
||||||
|
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 total = await model.count();
|
||||||
|
return { data, total };
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { PrismaClient } from '@repo/db';
|
import { PrismaClient } from '@repo/db';
|
||||||
import { PaginatedTable } from '../app/_components/PaginatedTable';
|
import { PaginatedTable } from './_components/PaginatedTable';
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
@@ -12,12 +12,17 @@ export default async function Home() {
|
|||||||
<button className="btn">Logout</button>
|
<button className="btn">Logout</button>
|
||||||
</Link>
|
</Link>
|
||||||
<PaginatedTable
|
<PaginatedTable
|
||||||
prismaGetter={prisma.user.findMany}
|
rowsPerPage={10}
|
||||||
|
prismaModel={'user'}
|
||||||
columns={[
|
columns={[
|
||||||
{
|
{
|
||||||
header: 'ID',
|
header: 'ID',
|
||||||
accessorKey: 'id',
|
accessorKey: 'id',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: 'Email',
|
||||||
|
accessorKey: 'email',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
header: 'First Name',
|
header: 'First Name',
|
||||||
accessorKey: 'firstname',
|
accessorKey: 'firstname',
|
||||||
@@ -25,6 +30,7 @@ export default async function Home() {
|
|||||||
{
|
{
|
||||||
header: 'Last Name',
|
header: 'Last Name',
|
||||||
accessorKey: 'lastname',
|
accessorKey: 'lastname',
|
||||||
|
footer: 'Total',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user