diff --git a/dashboard/15-final/app/dashboard/customers/page.tsx b/dashboard/15-final/app/dashboard/customers/page.tsx index c45ee90a..dcd62af5 100644 --- a/dashboard/15-final/app/dashboard/customers/page.tsx +++ b/dashboard/15-final/app/dashboard/customers/page.tsx @@ -4,12 +4,10 @@ import CustomersTable from '@/app/ui/customers/table'; export default async function Page({ searchParams, }: { - searchParams: - | { - query: string | undefined; - page: string | undefined; - } - | undefined; + searchParams?: { + query?: string; + page?: string; + }; }) { const query = searchParams?.query || ''; diff --git a/dashboard/15-final/app/dashboard/invoices/page.tsx b/dashboard/15-final/app/dashboard/invoices/page.tsx index 11bfce84..fcf178aa 100644 --- a/dashboard/15-final/app/dashboard/invoices/page.tsx +++ b/dashboard/15-final/app/dashboard/invoices/page.tsx @@ -8,15 +8,13 @@ import { lusitana } from '@/app/ui/fonts'; export default async function Page({ searchParams, }: { - searchParams: - | { - query: string | undefined; - page: string | undefined; - } - | undefined; + searchParams?: { + query?: string; + page?: string; + }; }) { const query = searchParams?.query || ''; - const currentPage = query ? 1 : Number(searchParams?.page || '1'); + const currentPage = Number(searchParams?.page || '1'); const { invoices, totalPages } = await fetchFilteredInvoices( query, diff --git a/dashboard/15-final/app/lib/utils.ts b/dashboard/15-final/app/lib/utils.ts index 4dce958c..b7f7cffe 100644 --- a/dashboard/15-final/app/lib/utils.ts +++ b/dashboard/15-final/app/lib/utils.ts @@ -34,3 +34,36 @@ export const generateYAxis = (revenue: Revenue[]) => { return { yAxisLabels, topLabel }; }; + +export const generatePagination = (currentPage: number, totalPages: number) => { + // If the total number of pages is 7 or less, + // display all pages without any ellipsis. + if (totalPages <= 7) { + return Array.from({ length: totalPages }, (_, i) => i + 1); + } + + // If the current page is among the first 3 pages, + // show the first 3, an ellipsis, and the last 2 pages. + if (currentPage <= 3) { + return [1, 2, 3, '...', totalPages - 1, totalPages]; + } + + // If the current page is among the last 3 pages, + // show the first 2, an ellipsis, and the last 3 pages. + if (currentPage >= totalPages - 2) { + return [1, 2, '...', totalPages - 2, totalPages - 1, totalPages]; + } + + // If the current page is somewhere in the middle, + // show the first page, an ellipsis, the current page and its neighbors, + // another ellipsis, and the last page. + return [ + 1, + '...', + currentPage - 1, + currentPage, + currentPage + 1, + '...', + totalPages, + ]; +}; diff --git a/dashboard/15-final/app/ui/invoices/pagination.tsx b/dashboard/15-final/app/ui/invoices/pagination.tsx index 5af0925b..a9c6dbaa 100644 --- a/dashboard/15-final/app/ui/invoices/pagination.tsx +++ b/dashboard/15-final/app/ui/invoices/pagination.tsx @@ -1,9 +1,10 @@ 'use client'; import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline'; -import { usePathname, useSearchParams } from 'next/navigation'; import clsx from 'clsx'; import Link from 'next/link'; +import { generatePagination } from '@/app/lib/utils'; +import { usePathname, useSearchParams } from 'next/navigation'; export default function Pagination({ currentPage, @@ -15,94 +16,114 @@ export default function Pagination({ const pathname = usePathname(); const searchParams = useSearchParams(); - const allPages = Array.from({ length: totalPages }, (_, i) => i + 1); - const PreviousPageTag = Link; - const NextPageTag = Link; - - const createPageUrl = (pageNumber: number | string) => { + const createPageURL = (pageNumber: number | string) => { const params = new URLSearchParams(searchParams); params.set('page', pageNumber.toString()); return `${pathname}?${params.toString()}`; }; - let pagesToShow = []; - - if (totalPages <= 7) { - pagesToShow = allPages; - } else if (currentPage <= 3) { - pagesToShow = [1, 2, 3, '...', totalPages - 1, totalPages]; - } else if (currentPage >= totalPages - 2) { - pagesToShow = [1, 2, '...', totalPages - 2, totalPages - 1, totalPages]; - } else { - pagesToShow = [ - 1, - '...', - currentPage - 1, - currentPage, - currentPage + 1, - '...', - totalPages, - ]; - } + const allPages = generatePagination(currentPage, totalPages); return (
- - - -
- {pagesToShow.map((page, i) => { - if (page === '...') { - return ( - - ... - - ); - } + + +
+ {allPages.map((page, index) => { + let position: 'first' | 'last' | 'single' | 'middle' | undefined; + + if (index === 0) position = 'first'; + if (index === allPages.length - 1) position = 'last'; + if (allPages.length === 1) position = 'single'; + if (page === '...') position = 'middle'; - const PageTag = page === currentPage || page === '...' ? 'p' : Link; return ( - - {page} - + href={createPageURL(page)} + page={page} + position={position} + isActive={currentPage === page} + /> ); })}
- - - + + = totalPages} + />
); } + +function PaginationNumber({ + page, + href, + isActive, + position, +}: { + page: number | string; + href: string; + position?: 'first' | 'last' | 'middle' | 'single'; + isActive: boolean; +}) { + const className = clsx( + 'flex h-10 w-10 items-center justify-center text-sm border', + { + 'rounded-l-md': position === 'first' || position === 'single', + 'rounded-r-md': position === 'last' || position === 'single', + 'z-10 bg-blue-600 border-blue-600 text-white': isActive, + 'hover:bg-gray-100': !isActive && position !== 'middle', + 'text-gray-300': position === 'middle', + }, + ); + + return isActive || position === 'middle' ? ( +
{page}
+ ) : ( + + {page} + + ); +} + +function PaginationArrow({ + href, + direction, + isDisabled, +}: { + href: string; + direction: 'left' | 'right'; + isDisabled?: boolean; +}) { + const className = clsx( + 'flex h-10 w-10 items-center justify-center rounded-md border', + { + 'pointer-events-none text-gray-300': isDisabled, + 'hover:bg-gray-100': !isDisabled, + 'mr-2 md:mr-4': direction === 'left', + 'ml-2 md:ml-4': direction === 'right', + }, + ); + + const icon = + direction === 'left' ? ( + + ) : ( + + ); + + return isDisabled ? ( +
{icon}
+ ) : ( + + {icon} + + ); +} diff --git a/dashboard/15-final/app/ui/search.tsx b/dashboard/15-final/app/ui/search.tsx index bb589945..7c890546 100644 --- a/dashboard/15-final/app/ui/search.tsx +++ b/dashboard/15-final/app/ui/search.tsx @@ -13,6 +13,8 @@ export default function Search({ placeholder }: { placeholder: string }) { console.log(`Searching... ${term}`); const params = new URLSearchParams(searchParams); + + params.set('page', '1'); if (term) { params.set('query', term); } else {