Skip to content

Commit

Permalink
pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
nlkluth committed Nov 7, 2023
1 parent b37c9d7 commit d78e74a
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 78 deletions.
98 changes: 20 additions & 78 deletions packages/nextjs/components/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import * as React from "react";
import { Pagination as BasePagination } from "shared-ui";
import Link from "next/link";
import { useRouter } from "next/router";
import { FaChevronLeft, FaChevronRight } from "react-icons/fa";
import classNames from "classnames";
import { motion } from "framer-motion";

type PaginationProps = {
pageCount: number;
Expand All @@ -12,88 +10,32 @@ type PaginationProps = {
};

export const Pagination = ({ onPageChange, pageCount = 1, currentPage = 1 }: PaginationProps) => {
const router = useRouter();
const { page: _page, ...otherQuery } = router.query;
const baseUrlObj = {
pathname: router.pathname,
query: otherQuery,
};
const getUrlObjWithPage = (pageNum: number) => ({
...baseUrlObj,
query: { ...baseUrlObj.query, page: pageNum.toString() },
});

const totalPages = Array.from({ length: pageCount }, (_item, index) => index + 1);

const handlePageChanged = (e: React.MouseEvent<HTMLAnchorElement>, page: number) => {
if (onPageChange) {
e.preventDefault();
onPageChange(page);
}
};

const prevUrlObj = currentPage <= 2 ? baseUrlObj : getUrlObjWithPage(currentPage - 1);
const nextUrlObj = currentPage >= pageCount ? baseUrlObj : getUrlObjWithPage(currentPage + 1);

return (
<motion.nav className="flex items-center justify-between text-primary" layoutId="pagination-nav">
<MaybeDisabledLink
urlObject={prevUrlObj}
isDisabled={currentPage <= 1}
className="inline-flex items-center gap-2 leading-none"
>
<FaChevronLeft className="h-5 w-5" aria-hidden="true" />
Previous
</MaybeDisabledLink>
<div className="flex gap-x-1">
{totalPages.map((page) => (
<Link key={`page-${page}`} href={page === 1 ? baseUrlObj : getUrlObjWithPage(page)} passHref legacyBehavior>
<a
onClick={(e) => handlePageChanged(e, page)}
className={classNames(
"border rounded w-10 aspect-square flex items-center justify-center",
page === currentPage ? "border-primary" : "border-[transparent]"
)}
aria-current={page === currentPage ? "page" : "false"}
>
{page}
</a>
</Link>
))}
</div>
<MaybeDisabledLink
urlObject={nextUrlObj}
isDisabled={currentPage >= pageCount}
className="inline-flex items-center gap-2 leading-none"
>
Next
<FaChevronRight className="h-5 w-5" aria-hidden="true" />
</MaybeDisabledLink>
</motion.nav>
);
};

const MaybeDisabledLink = ({
isDisabled,
urlObject,
className,
children,
}: React.PropsWithChildren<{
isDisabled?: boolean;
className?: string;
urlObject: any;
}>) => {
if (!isDisabled) {
return (
<Link href={urlObject} className={className}>
{children}
</Link>
);
}

return (
<span aria-disabled className={classNames(className, "opacity-60")}>
{children}
</span>
<BasePagination
pageCount={pageCount}
NextPreviousLink={Link}
currentPage={currentPage}
renderPaginationLink={({ page, href }) => (
<Link key={`page-${page}`} href={href} passHref legacyBehavior>
<a
onClick={(e) => handlePageChanged(e, page)}
className={classNames(
"border rounded w-10 aspect-square flex items-center justify-center",
page === currentPage ? "border-primary" : "border-[transparent]"
)}
aria-current={page === currentPage ? "page" : "false"}
>
{page}
</a>
</Link>
)}
/>
);
};
87 changes: 87 additions & 0 deletions packages/shared-ui/components/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import * as React from "react";
import { FaChevronLeft, FaChevronRight } from "react-icons/fa";
import classNames from "classnames";
import { motion } from "framer-motion";

type PaginationProps = {
pageCount: number;
currentPage?: number;
onPageChange?: (page: number) => void;
NextPreviousLink: React.ElementType;
renderPaginationLink: ({ page, href }: { page: number; href: string }) => JSX.Element;
};

export const Pagination = ({
pageCount = 1,
currentPage = 1,
renderPaginationLink,
NextPreviousLink,
}: PaginationProps) => {
const url = new URL(window.location.href);
const params = new URLSearchParams(url.search);
const getUrlWithPage = (pageNum: number) => {
params.set("page", pageNum.toString());
return `${url.pathname}?${params}`;
};

const totalPages = Array.from({ length: pageCount }, (_item, index) => index + 1);

const prevUrl = currentPage <= 2 ? url.toString() : getUrlWithPage(currentPage - 1);
const nextUrl = currentPage >= pageCount ? url.toString() : getUrlWithPage(currentPage + 1);

return (
<motion.nav className="flex items-center justify-between text-primary" layoutId="pagination-nav">
<MaybeDisabledLink
href={prevUrl}
as={NextPreviousLink}
isDisabled={currentPage <= 1}
className="inline-flex items-center gap-2 leading-none"
>
<FaChevronLeft className="h-5 w-5" aria-hidden="true" />
Previous
</MaybeDisabledLink>
<div className="flex gap-x-1">
{totalPages.map((page) =>
renderPaginationLink({ page, href: page === 1 ? url.toString() : getUrlWithPage(page) })
)}
</div>
<MaybeDisabledLink
as={NextPreviousLink}
href={nextUrl}
isDisabled={currentPage >= pageCount}
className="inline-flex items-center gap-2 leading-none"
>
Next
<FaChevronRight className="h-5 w-5" aria-hidden="true" />
</MaybeDisabledLink>
</motion.nav>
);
};

const MaybeDisabledLink = ({
isDisabled,
href,
className,
children,
as = "a",
}: React.PropsWithChildren<{
isDisabled?: boolean;
className?: string;
href: string;
as?: React.ElementType;
}>) => {
if (!isDisabled) {
const Link = as;
return (
<Link href={href} className={className}>
{children}
</Link>
);
}

return (
<span aria-disabled className={classNames(className, "opacity-60")}>
{children}
</span>
);
};
1 change: 1 addition & 0 deletions packages/shared-ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export * from "./components/WeDontSellBreadBanner";
export * from "./components/Price";
export * from "./components/QuantityInput";
export * from './components/ProductSort';
export * from './components/Pagination';

export * from "./components/sanity";
export * from "./components/cart";
Expand Down

0 comments on commit d78e74a

Please sign in to comment.