PasstDazu driven by Products.relatedProduct; circle back on Focus icons
- PasstDazu.tsx now takes a productSlug prop and reads its cross-sell target from the product's own relatedProduct field (Payload) instead of hardcoding "todo-karten" — reusable on any product page now. - payload.ts: Product/PayloadProduct gained relatedProduct, resolved via a bounded-recursion mapPayloadProduct call (safe — the fetch's depth:2 means the nested relation's own relatedProduct is never populated). - Focus.tsx icons: added the black stroked circle back around each glyph (matches icon-step-3.png exactly) — dropped in the previous pass by mistake while fixing the color/fill.
This commit is contained in:
@@ -27,6 +27,7 @@ const product = (overrides: Partial<Product> = {}): Product => ({
|
||||
taxRatePercent: null,
|
||||
noShippingCost: false,
|
||||
categories: [],
|
||||
relatedProduct: null,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
|
||||
@@ -251,6 +251,12 @@ export type Product = {
|
||||
// than "matches none", since an uncategorized product shouldn't just
|
||||
// disappear the moment a category filter is applied.
|
||||
categories: string[];
|
||||
// Optional cross-sell pick (Products.relatedProduct) — powers a "Passt
|
||||
// dazu" card on the product's own detail page, same field/pattern as
|
||||
// Posts.relatedProduct. null means no card. Only one level deep (this
|
||||
// related product's own relatedProduct is never resolved/shown) — see
|
||||
// mapPayloadProduct's own comment.
|
||||
relatedProduct: Product | null;
|
||||
};
|
||||
|
||||
type PayloadProduct = {
|
||||
@@ -288,6 +294,7 @@ type PayloadProduct = {
|
||||
}[]
|
||||
| null;
|
||||
categories: ({ name: string } | number)[] | null;
|
||||
relatedProduct: PayloadProduct | number | null;
|
||||
};
|
||||
|
||||
// A product/variant is only actually unbuyable when it opted into
|
||||
@@ -354,6 +361,10 @@ export function mapPayloadProduct(product: PayloadProduct): Product {
|
||||
categories: (product.categories ?? [])
|
||||
.map((c) => (typeof c === "object" && c ? c.name : null))
|
||||
.filter((name): name is string => Boolean(name)),
|
||||
// Recursive call is safe here — depth=2 on the originating fetch means
|
||||
// this nested object's OWN relatedProduct is never populated (stays a
|
||||
// raw id or absent), so the recursion bottoms out after exactly one level.
|
||||
relatedProduct: typeof product.relatedProduct === "object" && product.relatedProduct ? mapPayloadProduct(product.relatedProduct) : null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user