diff --git a/app/components/ProductBlocks.tsx b/app/components/ProductBlocks.tsx
index 015fa5e..c6fe618 100644
--- a/app/components/ProductBlocks.tsx
+++ b/app/components/ProductBlocks.tsx
@@ -1,13 +1,15 @@
import Link from "next/link";
import Image from "next/image";
import type { Product, ProductBlock, PageBlock } from "../lib/payload";
-import { getShippingSettings, getDefaultTaxRatePercent, getKleinunternehmer } from "../lib/payload";
+import { getShippingSettings, getDefaultTaxRatePercent, getKleinunternehmer, getTestimonials } from "../lib/payload";
import { formatPrice, discountPercent } from "../lib/format";
import { effectiveTaxRate } from "../lib/cartTotals";
import { AddToCartButton } from "./AddToCartButton";
import { ProductName } from "./ProductName";
import { RichText } from "./RichText";
+import { Reveal } from "./Reveal";
import { renderPageBlockSync } from "./PageBlocks";
+import { TestimonialsGrid } from "./TestimonialsGrid";
// Renders a Payload Products document's `layout` blocks field — same
// "page sections, not inline Lexical nodes" shape as PageBlocks.tsx, which
@@ -26,15 +28,37 @@ export async function ProductBlocks({ product }: { product: Product }) {
]);
const ctx: ProductBlockContext = { product, shipping, taxRate: effectiveTaxRate(product, defaultTaxRate), kleinunternehmer };
- return (
- <>
- {product.layout.map((block) => (
-
+ const rendered = await Promise.all(
+ product.layout.map(async (block) => {
+ // Needs its own async data fetch — same reason PageBlocks.tsx
+ // handles this one block type in its own outer async map instead of
+ // the sync switch below (renderProductBlock/renderPageBlockSync).
+ if (block.blockType === "testimonialsRef") {
+ const testimonials = await getTestimonials(block.page);
+ if (testimonials.length === 0) return null;
+ return (
+
+
+
+ );
+ }
+ // productHero/productPricingPanel render their own full section
+ // (edge-to-edge image, own Reveal, own padding rhythm) — matching
+ // the hand-coded PDPs (todo-cards etc.) precisely needed each of
+ // those, unlike a generic content block, so they opt out of this
+ // shared wrapper entirely rather than fighting it.
+ if (block.blockType === "productHero" || block.blockType === "productPricingPanel") {
+ return