feat: add functionality to the Pagination component

This commit is contained in:
Pablo Lara
2024-08-09 11:54:58 +02:00
parent bed2b1e7f7
commit 5bb3c012c9
8 changed files with 100 additions and 180 deletions
+4 -13
View File
@@ -1,16 +1,12 @@
"use server";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { parseStringify } from "@/lib";
interface PaginationOptions {
page?: number;
}
export const getProvider = async ({ page = 1 }: PaginationOptions) => {
if (isNaN(Number(page))) page = 1;
if (page < 1) page = 1;
export const getProvider = async ({ page = 1 }) => {
if (isNaN(Number(page)) || page < 1) redirect("/providers");
const keyServer = process.env.LOCAL_SERVER_URL;
@@ -26,12 +22,7 @@ export const getProvider = async ({ page = 1 }: PaginationOptions) => {
const data = await providers.json();
const parsedData = parseStringify(data);
revalidatePath("/providers");
return {
providerDetails: parsedData?.data,
currentPage: parsedData?.meta?.pagination?.page,
totalPages: parsedData?.meta?.pagination?.pages,
totalItems: parsedData?.meta?.pagination?.count,
};
return parsedData;
} catch (error) {
console.error("Error fetching providers:", error);
return undefined;
+14 -34
View File
@@ -9,16 +9,10 @@ import {
DataTableProvider,
SkeletonTableProvider,
} from "@/components/providers";
import { Header, Pagination } from "@/components/ui";
import { Header } from "@/components/ui";
import { searchParamsProps } from "@/types";
export default async function Providers({
searchParams,
}: {
searchParams: {
page: number;
};
}) {
console.log({ searchParams }, "los searchParamsss!");
export default async function Providers({ searchParams }: searchParamsProps) {
return (
<>
<Header title="Providers" icon="fluent:cloud-sync-24-regular" />
@@ -36,32 +30,18 @@ export default async function Providers({
);
}
const SSRDataTable = async ({
searchParams,
}: {
searchParams: {
page: number;
};
}) => {
// const perPage = searchParams['per_page'] ?? '5'
// const page = searchParams.page ? parseInt(searchParams.page) : 1;
const providersData = await getProvider({});
// const [providers] = await Promise.all([providersData]);
// const { providerDetails, currentPage, totalPages, totalItems } = providersData;
// console.log(currentPage, totalPages, 'hehe')
// if (providers.meta.pagination.count === 0) {
// redirect('/');
// }
// console.log(providers);
// const currentPage = providers.meta.pagination.page;
// const pages = providers.meta.pagination.pages;
// const count = providers.meta.pagination.count;
const SSRDataTable = async ({ searchParams }: searchParamsProps) => {
const page = searchParams.page ? parseInt(searchParams.page) : 1;
const providersData = await getProvider({ page });
const [providers] = await Promise.all([providersData]);
if (providers?.errors) redirect("/providers");
// console.log(`Pages: ${pages}, Count: ${count}`);
return (
<>
{/* <DataTableProvider columns={ColumnsProvider} data={providerDetails ?? []} /> */}
{/* <Pagination totalPages={totalPages} currentPage={currentPage} /> */}
</>
<DataTableProvider
columns={ColumnsProvider}
data={providers?.data ?? []}
metadata={providers?.meta}
/>
);
};
@@ -1,65 +1,83 @@
import { Button } from "@nextui-org/react";
"use client";
import {
ChevronLeftIcon,
ChevronRightIcon,
DoubleArrowLeftIcon,
DoubleArrowRightIcon,
} from "@radix-ui/react-icons";
import { type Table } from "@tanstack/react-table";
import Link from "next/link";
import { redirect, usePathname, useSearchParams } from "next/navigation";
interface DataTablePaginationProps<TData> {
table: Table<TData>;
import { extractPaginationInfo } from "@/lib";
import { MetaDataProps } from "@/types";
interface DataTablePaginationProps {
pageSizeOptions?: number[];
metadata?: MetaDataProps;
}
export function DataTablePagination<TData>({
table,
}: DataTablePaginationProps<TData>) {
// console.log(table);
export function DataTablePagination({ metadata }: DataTablePaginationProps) {
if (!metadata) return null;
const pathname = usePathname();
const searchParams = useSearchParams();
const { currentPage, totalPages, totalEntries } =
extractPaginationInfo(metadata);
const createPageUrl = (pageNumber: number | string) => {
const params = new URLSearchParams(searchParams);
if (pageNumber === "...") return `${pathname}?${params.toString()}`;
if (+pageNumber > totalPages) {
return `${pathname}?${params.toString()}`;
}
params.set("page", pageNumber.toString());
return `${pathname}?${params.toString()}`;
};
return (
<div className="flex w-full flex-col-reverse items-center justify-between gap-4 overflow-auto p-1 sm:flex-row sm:gap-8">
<div className="whitespace-nowrap text-sm font-medium">
{totalEntries} entries in Total.
</div>
<div className="flex flex-col-reverse items-center gap-4 sm:flex-row sm:gap-6 lg:gap-8">
<div className="flex items-center justify-center text-sm font-medium">
Page {table.getState().pagination.pageIndex + 1} of{" "}
{table.getPageCount()}
Page {currentPage} of {totalPages}
</div>
<div className="flex items-center space-x-2">
<Button
<Link
aria-label="Go to first page"
variant="light"
className="hidden size-8 p-0 lg:flex"
onClick={() => table.setPageIndex(0)}
disabled={!table.getCanPreviousPage()}
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
href={createPageUrl(1)}
aria-disabled="true"
>
<DoubleArrowLeftIcon className="size-4" aria-hidden="true" />
</Button>
<Button
</Link>
<Link
aria-label="Go to previous page"
variant="light"
className="size-8"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
href={createPageUrl(currentPage - 1)}
aria-disabled="true"
>
<ChevronLeftIcon className="size-4" aria-hidden="true" />
</Button>
<Button
</Link>
<Link
aria-label="Go to next page"
variant="light"
className="size-8"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
href={createPageUrl(currentPage + 1)}
>
<ChevronRightIcon className="size-4" aria-hidden="true" />
</Button>
<Button
</Link>
<Link
aria-label="Go to last page"
variant="light"
className="hidden size-8 lg:flex"
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
disabled={!table.getCanNextPage()}
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
href={createPageUrl(totalPages)}
>
<DoubleArrowRightIcon className="size-4" aria-hidden="true" />
</Button>
</Link>
</div>
</div>
</div>
@@ -19,20 +19,22 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table/Table";
import { MetaDataProps } from "@/types";
import { DataTablePagination } from "./DataTablePagination";
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
metadata?: MetaDataProps;
}
export function DataTableProvider<TData, TValue>({
columns,
data,
metadata,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = useState<SortingState>([]);
const table = useReactTable({
data,
columns,
@@ -97,8 +99,8 @@ export function DataTableProvider<TData, TValue>({
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<DataTablePagination table={table} />
<div className="flex items-center w-full space-x-2 py-4">
<DataTablePagination metadata={metadata} />
</div>
</>
);
-1
View File
@@ -1,7 +1,6 @@
export * from "./alert/Alert";
export * from "./dialog/Dialog";
export * from "./header/Header";
export * from "./pagination/Pagination";
export * from "./select/Select";
export * from "./sidebar";
export * from "./table/StatusBadge";
-95
View File
@@ -1,95 +0,0 @@
"use client";
import Link from "next/link";
import { usePathname, useSearchParams } from "next/navigation";
import React from "react";
interface Props {
totalPages: number;
currentPage: number;
nextPage?: string;
}
export const Pagination = ({ totalPages, currentPage }: Props) => {
const pathname = usePathname();
const searchParams = useSearchParams();
// const currentPage = searchParams["page"] ?? "1";
const createPageUrl = (pageNumber: number | string) => {
const params = new URLSearchParams(searchParams);
if (pageNumber === "...") return `${pathname}?${params.toString()}`;
if (+pageNumber <= 0) {
return `${pathname}`;
}
if (+pageNumber > totalPages) {
return `${pathname}?${params.toString()}`;
}
params.set("page", pageNumber.toString());
return `${pathname}?${params.toString()}`;
};
console.log(pathname, searchParams, currentPage);
return (
<div className="flex justify-center">
<nav aria-label="Page navigation example">
<ul className="flex list-style-none">
<li className="page-item">
<Link
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
href={createPageUrl(currentPage - 1)}
aria-disabled="true"
>
Previous
</Link>
</li>
<li className="page-item">
<a
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
href="#"
>
1
</a>
</li>
<li className="page-item active">
<a
className="page-link relative block py-1.5 px-3 border-0 bg-blue-600 outline-none transition-all duration-300 rounded text-white hover:text-white hover:bg-blue-600 shadow-md focus:shadow-md"
href="#"
>
2 <span className="visually-hidden"></span>
</a>
</li>
<li className="page-item">
<a
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
href="#"
>
3
</a>
</li>
<li className="page-item">
<a
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
href="#"
>
...
</a>
</li>
<li className="page-item">
<Link
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
href={"#"}
>
Next
</Link>
</li>
</ul>
</nav>
</div>
);
};
+10
View File
@@ -1,6 +1,8 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { MetaDataProps } from "@/types";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
@@ -9,6 +11,14 @@ export const parseStringify = (value: any) => JSON.parse(JSON.stringify(value));
export const convertFileToUrl = (file: File) => URL.createObjectURL(file);
export const extractPaginationInfo = (metadata: MetaDataProps) => {
const currentPage = metadata?.pagination.page ?? "1";
const totalPages = metadata?.pagination.pages;
const totalEntries = metadata?.pagination.count;
return { currentPage, totalPages, totalEntries };
};
// FORMAT DATE TIME
export const formatDateTime = (
dateString: Date | string,
+15
View File
@@ -9,6 +9,12 @@ export type IconProps = {
style?: React.CSSProperties;
};
export interface searchParamsProps {
searchParams: {
page?: string;
};
}
export interface ProviderProps {
id: string;
type: "providers";
@@ -47,3 +53,12 @@ export interface FindingsProps {
account: string;
};
}
export interface MetaDataProps {
pagination: {
page: number;
pages: number;
count: number;
};
version: string;
}