mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
feat: add functionality to the Pagination component
This commit is contained in:
+4
-13
@@ -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;
|
||||
|
||||
@@ -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,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";
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user