diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 17c2fb4..be79e92 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -160,7 +160,8 @@ "Bash(curl -s http://127.0.0.1:3000/made-to-order)", "Bash(curl -s \"http://127.0.0.1:3000/products/awd-hoodie\")", "Bash(git commit -m 'Fix: NavDropdown link navigation with stopPropagation *)", - "Bash(git commit -m 'Feat: Remove all filters from products pages *)" + "Bash(git commit -m 'Feat: Remove all filters from products pages *)", + "Bash(git commit -m 'Feat: Add loading spinner for made-to-order page *)" ] } } diff --git a/src/app/made-to-order/page.tsx b/src/app/made-to-order/page.tsx index d29d160..912e821 100644 --- a/src/app/made-to-order/page.tsx +++ b/src/app/made-to-order/page.tsx @@ -2,6 +2,8 @@ import { prisma } from '@/lib/prisma'; import { toProductDTO } from '@/lib/product'; import { fetchActivePromotions } from '@/lib/promotions'; import ProductCard from '@/components/ProductCard'; +import LoadingSpinner from '@/components/LoadingSpinner'; +import { Suspense } from 'react'; type SearchParams = { page?: string; @@ -9,13 +11,7 @@ type SearchParams = { const PRODUCTS_PER_PAGE = 20; -function toArray(v?: string | string[]) { - if (!v) return []; - return Array.isArray(v) ? v : [v]; -} - -export default async function ProductsPage({ searchParams }: { searchParams: SearchParams }) { - const currentPage = Math.max(1, Number(searchParams.page) || 1); +async function ProductsGrid({ currentPage }: { currentPage: number }) { const activePromotions = await fetchActivePromotions(); const [rows, totalCount] = await Promise.all([ @@ -31,6 +27,13 @@ export default async function ProductsPage({ searchParams }: { searchParams: Sea const products = rows.map((p) => toProductDTO(p, activePromotions, 'personalised')); const totalPages = Math.ceil(totalCount / PRODUCTS_PER_PAGE); + return { products, totalPages, totalCount, currentPage }; +} + +export default async function ProductsPage({ searchParams }: { searchParams: SearchParams }) { + const currentPage = Math.max(1, Number(searchParams.page) || 1); + const totalCount = await prisma.product.count({ where: { showOnPersonalised: true } }); + return (
@@ -40,47 +43,56 @@ export default async function ProductsPage({ searchParams }: { searchParams: Sea

-
- {/* Sidebar filters */} - {products.length === 0 ? ( -
-

Nothing here yet

-

Templates will show up here once created.

+ }> + + +
+ ); +} + +async function ProductsGridContent({ currentPage, totalCount }: { currentPage: number; totalCount: number }) { + const { products, totalPages } = await ProductsGrid({ currentPage }); + + return ( +
+ {products.length === 0 ? ( +
+

Nothing here yet

+

Templates will show up here once created.

+
+ ) : ( +
+
+ {products.map((p) => ( + + ))}
- ) : ( -
-
- {products.map((p) => ( - - ))} + + {totalPages > 1 && ( +
+ {currentPage > 1 && ( + + ← Previous + + )} +

+ Page {currentPage} of {totalPages} +

+ {currentPage < totalPages && ( + + Next → + + )}
- - {totalPages > 1 && ( -
- {currentPage > 1 && ( - - ← Previous - - )} -

- Page {currentPage} of {totalPages} -

- {currentPage < totalPages && ( - - Next → - - )} -
- )} -
- )} -
+ )} +
+ )}
); } diff --git a/src/components/LoadingSpinner.tsx b/src/components/LoadingSpinner.tsx new file mode 100644 index 0000000..d1256fd --- /dev/null +++ b/src/components/LoadingSpinner.tsx @@ -0,0 +1,10 @@ +export default function LoadingSpinner() { + return ( +
+
+
+
+
+
+ ); +}