diff --git a/app/shop/components/ProductGrid.tsx b/app/shop/components/ProductGrid.tsx index 499267c..5391d61 100644 --- a/app/shop/components/ProductGrid.tsx +++ b/app/shop/components/ProductGrid.tsx @@ -13,7 +13,29 @@ import { WishlistButton } from "../../components/WishlistButton"; // there's no reason to pay for a client fetch when a server one already // gives faster first paint and no loading flash. -export async function ProductGrid() { +// Products have no category taxonomy today (only Posts do) — a "N +// checkboxes" category sidebar isn't buildable against real data yet, so +// this only covers price, the one dimension that already exists on every +// product. 3 buckets split evenly across the active catalog's actual +// min/max price (not fixed round-number thresholds like "unter 20 €") so +// the ranges stay sensible regardless of what's actually being sold — +// re-computed on every request from whatever's active, never stale. +function buildPriceBuckets(products: { price: number }[]): { label: string; min: number; max: number }[] { + if (products.length === 0) return []; + const prices = products.map((p) => p.price); + const min = Math.min(...prices); + const max = Math.max(...prices); + if (min === max) return []; + const step = (max - min) / 3; + const bounds = [min, min + step, min + step * 2, max]; + return [0, 1, 2].map((i) => ({ + label: i === 0 ? `bis ${formatPrice(bounds[i + 1])}` : i === 2 ? `ab ${formatPrice(bounds[i])}` : `${formatPrice(bounds[i])}–${formatPrice(bounds[i + 1])}`, + min: bounds[i], + max: bounds[i + 1], + })); +} + +export async function ProductGrid({ searchParams }: { searchParams?: { priceBucket?: string } }) { const [allProducts, shipping, defaultTaxRate, kleinunternehmer, wishlistEnabled] = await Promise.all([ getProducts(), getShippingSettings(), @@ -21,9 +43,9 @@ export async function ProductGrid() { getKleinunternehmer(), getWishlistEnabled(), ]); - const products = allProducts.filter((p) => p.active); + const allActiveProducts = allProducts.filter((p) => p.active); - if (products.length === 0) { + if (allActiveProducts.length === 0) { return (

Aktuell keine Produkte verfügbar.

@@ -31,8 +53,45 @@ export async function ProductGrid() { ); } + const priceBuckets = buildPriceBuckets(allActiveProducts); + const activeBucketIndex = searchParams?.priceBucket ? Number(searchParams.priceBucket) : null; + const activeBucket = activeBucketIndex !== null ? priceBuckets[activeBucketIndex] : undefined; + const products = activeBucket + ? allActiveProducts.filter((p) => p.price >= activeBucket.min && p.price <= activeBucket.max) + : allActiveProducts; + return (
+ {priceBuckets.length > 0 && ( +
+ + Alle Preise + + {priceBuckets.map((bucket, i) => ( + + {bucket.label} + + ))} +
+ )} + + {products.length === 0 &&

Keine Produkte in dieser Preisspanne gefunden.

} + {/* 2-up from the mobile breakpoint (sm, 640px) through 1023px — was sm:grid-cols-12 with each card sm:col-span-3 (4-up), too narrow a card through that tablet range. 4-up now only kicks in at lg diff --git a/app/shop/page.tsx b/app/shop/page.tsx index 7c029d5..8017512 100644 --- a/app/shop/page.tsx +++ b/app/shop/page.tsx @@ -19,12 +19,17 @@ export const metadata: Metadata = { }, }; -export default function ShopPage() { +export default async function ShopPage({ + searchParams, +}: { + searchParams: Promise<{ priceBucket?: string }>; +}) { + const resolvedSearchParams = await searchParams; return ( <>
- +