diff --git a/app/search/(collection)/[...collection]/page.tsx b/app/search/(collection)/[...collection]/page.tsx
index 1f8d4dfbf..67e3c326d 100644
--- a/app/search/(collection)/[...collection]/page.tsx
+++ b/app/search/(collection)/[...collection]/page.tsx
@@ -4,6 +4,7 @@ import { notFound } from 'next/navigation';
import Grid from 'components/grid';
import ProductGridItems from 'components/layout/product-grid-items';
+import Pagination from 'components/collection/pagination';
import { defaultSort, sorting } from 'lib/constants';
export const runtime = 'edge';
@@ -34,7 +35,7 @@ export default async function CategoryPage({
const { sort, page } = searchParams as { [key: string]: string };
const { sortKey, reverse } = sorting.find((item) => item.slug === sort) || defaultSort;
- const products = await getCollectionProducts({
+ const { products, total, limit } = await getCollectionProducts({
collection: params.collection,
page: page ? parseInt(page) : 1,
sortKey,
@@ -46,9 +47,14 @@ export default async function CategoryPage({
{products.length === 0 ? (
{`No products found in this collection`}
) : (
-
-
-
+
)}
);
diff --git a/components/collection/pagination.tsx b/components/collection/pagination.tsx
new file mode 100644
index 000000000..ad3692498
--- /dev/null
+++ b/components/collection/pagination.tsx
@@ -0,0 +1,68 @@
+'use client'
+
+import ReactPaginate from 'react-paginate';
+import { createUrl } from 'lib/utils';
+import { usePathname, useSearchParams, useRouter } from 'next/navigation';
+
+export default function Pagination({ itemsPerPage, itemsTotal, currentPage }: { itemsPerPage: number, itemsTotal: number, currentPage: number }) {
+ const router = useRouter();
+ const pathname = usePathname();
+ const currentParams = useSearchParams();
+ const q = currentParams.get('q');
+ const sort = currentParams.get('sort');
+ const pageCount = Math.ceil(itemsTotal / itemsPerPage);
+
+ // Invoke when user click to request another page.
+ const handlePageClick = (event: clickEvent) => {
+ const page = event.selected;
+ const newPage = page + 1;
+ let newUrl = createUrl(pathname, new URLSearchParams({
+ ...(q && { q }),
+ ...(sort && { sort }),
+ }));
+ if (page !== 0) {
+ newUrl = createUrl(pathname, new URLSearchParams({
+ ...(q && { q }),
+ ...(sort && { sort }),
+ page: newPage.toString(),
+ }));
+ }
+ router.replace(newUrl);
+ };
+
+ return (
+ <>
+
+ >
+ );
+}
+
+type clickEvent = {
+ index: number | null;
+ selected: number;
+ nextSelectedPage: number | undefined;
+ event: object;
+ isPrevious: boolean;
+ isNext: boolean;
+ isBreak: boolean;
+ isActive: boolean;
+}
\ No newline at end of file
diff --git a/components/grid/three-items.tsx b/components/grid/three-items.tsx
index a47af2ed5..a7d2b9010 100644
--- a/components/grid/three-items.tsx
+++ b/components/grid/three-items.tsx
@@ -37,7 +37,7 @@ function ThreeItemGridItem({
export async function ThreeItemGrid() {
// Collections that start with `hidden-*` are hidden from the search page.
- const homepageItems = await getCollectionProducts({
+ const { products: homepageItems } = await getCollectionProducts({
collection: 'Summer-BBQ/Hidden-Category'
});
diff --git a/components/layout/search/filter/item.tsx b/components/layout/search/filter/item.tsx
index 1a3b73ad3..6f02b9483 100644
--- a/components/layout/search/filter/item.tsx
+++ b/components/layout/search/filter/item.tsx
@@ -40,6 +40,7 @@ function SortFilterItem({ item }: { item: SortFilterItem }) {
const searchParams = useSearchParams();
const [active, setActive] = useState(searchParams.get('sort') === item.slug);
const q = searchParams.get('q');
+ const page = searchParams.get('page');
useEffect(() => {
setActive(searchParams.get('sort') === item.slug);
@@ -51,6 +52,7 @@ function SortFilterItem({ item }: { item: SortFilterItem }) {
pathname,
new URLSearchParams({
...(q && { q }),
+ ...(page && { page }),
sort: item.slug
})
)
diff --git a/lib/shopware/index.ts b/lib/shopware/index.ts
index 717380b19..b46bdc920 100644
--- a/lib/shopware/index.ts
+++ b/lib/shopware/index.ts
@@ -109,7 +109,7 @@ export async function getCollectionProducts(params?: {
sortKey?: string;
categoryId?: string;
defaultSearchCriteria?: Partial;
-}): Promise {
+}): Promise<{ products: Product[]; total: number; limit: number }> {
let res;
let category = params?.categoryId;
const collectionName = transformHandle(params?.collection ?? '');
@@ -136,7 +136,9 @@ export async function getCollectionProducts(params?: {
res = await requestCategoryProductsCollection(category, productsCriteria);
}
- return res ? transformProducts(res) : [];
+ return res
+ ? { products: transformProducts(res), total: res.total ?? 0, limit: res.limit ?? 0 }
+ : { products: [], total: 0, limit: 0 };
}
export async function getCategory(
diff --git a/package.json b/package.json
index f749df541..e2a1e9fdd 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,8 @@
"next": "13.4.9",
"react": "18.2.0",
"react-cookie": "^4.1.1",
- "react-dom": "18.2.0"
+ "react-dom": "18.2.0",
+ "react-paginate": "^8.2.0"
},
"devDependencies": {
"@playwright/test": "^1.35.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1be262caa..7d0d18cd1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -28,6 +28,9 @@ dependencies:
react-dom:
specifier: 18.2.0
version: 18.2.0(react@18.2.0)
+ react-paginate:
+ specifier: ^8.2.0
+ version: 8.2.0(react@18.2.0)
devDependencies:
'@playwright/test':
@@ -2411,7 +2414,6 @@ packages:
/object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
- dev: true
/object-hash@3.0.0:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
@@ -2811,7 +2813,6 @@ packages:
loose-envify: 1.4.0
object-assign: 4.1.1
react-is: 16.13.1
- dev: true
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
@@ -2846,6 +2847,15 @@ packages:
/react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+ /react-paginate@8.2.0(react@18.2.0):
+ resolution: {integrity: sha512-sJCz1PW+9PNIjUSn919nlcRVuleN2YPoFBOvL+6TPgrH/3lwphqiSOgdrLafLdyLDxsgK+oSgviqacF4hxsDIw==}
+ peerDependencies:
+ react: ^16 || ^17 || ^18
+ dependencies:
+ prop-types: 15.8.1
+ react: 18.2.0
+ dev: false
+
/react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}