Ship tracking-codes Phase 2: cookie consent banner + gated script injection
CookieBanner.tsx (equally-weighted Akzeptieren/Ablehnen, TTDSG) +
useConsent() cookie hook + TrackingScripts.tsx render active
tracking-codes rows only once their consentCategory is actually
accepted ('necessary' always renders). Wired into layout.tsx via the
new getTrackingCodes() fetcher. This is what makes the Phase 1
backend collection (tracking-codes) actually usable end to end.
Also reworks NotifyMeForm back to always-visible input+button (better
UX than a collapse-to-reveal step) — the resulting taller CTA is now
reserved on every card via NotifyMeFormReservedSpace, an invisible
twin rendered behind the real button, so an in-stock card's row
height matches an out-of-stock sibling's without the grid's
row-stretch pushing buttons out of alignment.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import { useEffect, useRef, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import { addToCart, useCart } from "../lib/cart";
|
||||
import { useCartFly } from "./CartFly";
|
||||
import { NotifyMeForm } from "./NotifyMeForm";
|
||||
import { NotifyMeForm, NotifyMeFormReservedSpace } from "./NotifyMeForm";
|
||||
|
||||
// Exported so consumers like RelatedProducts.tsx can delay their own
|
||||
// follow-up UI changes (e.g. swapping out this exact card) until after
|
||||
@@ -113,35 +113,46 @@ export function AddToCartInlineButton({
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
{currentlyOutOfStock ? (
|
||||
// Replaces the button slot entirely rather than stacking below a
|
||||
// disabled "Ausverkauft" button — this component's collapsed idle
|
||||
// state is a single button, same height as the "In den Warenkorb"
|
||||
// button it replaces, so an out-of-stock card doesn't end up taller
|
||||
// than its in-stock siblings and stretch their own buttons down
|
||||
// (plain CSS Grid rows stretch to the tallest card — see
|
||||
// ProductGrid.tsx's own flex-1-spacer comment on why equal card
|
||||
// height matters here).
|
||||
<NotifyMeForm productId={numericId} variantName={variants.length > 0 ? (selectedVariant ?? "") : ""} />
|
||||
) : (
|
||||
<button
|
||||
ref={buttonRef}
|
||||
type="button"
|
||||
onClick={handleClick}
|
||||
disabled={disabled}
|
||||
className={`${base} ${stateClasses}`}
|
||||
>
|
||||
<span
|
||||
className={
|
||||
"text-body-sm transition-colors " +
|
||||
(disabled ? "text-text-muted" : added ? "font-semibold text-success" : "text-text-primary")
|
||||
}
|
||||
>
|
||||
{limitReached ? "Maximale Menge im Warenkorb" : added ? "Hinzugefügt ✓" : label}
|
||||
</span>
|
||||
<Image alt="" src="/icon-cart-outline.png" width={32} height={30} className="h-[1.875rem] w-8 object-contain" />
|
||||
</button>
|
||||
)}
|
||||
{/* grid + [grid-area:1/1] stack — NotifyMeFormReservedSpace (an
|
||||
invisible, non-interactive twin of NotifyMeForm's markup) always
|
||||
contributes its height here, even for an in-stock card that
|
||||
never shows the real form. Without it, only out-of-stock cards
|
||||
would be tall enough to need the input+button, and plain CSS
|
||||
Grid's row-stretch (ProductGrid.tsx has no explicit row height)
|
||||
would push every sibling card's button down to match whichever
|
||||
card in the row happens to be out of stock. */}
|
||||
<div className="relative grid w-full">
|
||||
<div className="invisible pointer-events-none [grid-area:1/1]">
|
||||
<NotifyMeFormReservedSpace />
|
||||
</div>
|
||||
{/* self-start, not the stretch default — the button's TOP edge is
|
||||
what must align across cards (ProductGrid.tsx's flex-1 spacer
|
||||
pins this whole block to a card's bottom already); the extra
|
||||
reserved height below a single button just stays blank. */}
|
||||
<div className="[grid-area:1/1] self-start">
|
||||
{currentlyOutOfStock ? (
|
||||
<NotifyMeForm productId={numericId} variantName={variants.length > 0 ? (selectedVariant ?? "") : ""} />
|
||||
) : (
|
||||
<button
|
||||
ref={buttonRef}
|
||||
type="button"
|
||||
onClick={handleClick}
|
||||
disabled={disabled}
|
||||
className={`${base} ${stateClasses}`}
|
||||
>
|
||||
<span
|
||||
className={
|
||||
"text-body-sm transition-colors " +
|
||||
(disabled ? "text-text-muted" : added ? "font-semibold text-success" : "text-text-primary")
|
||||
}
|
||||
>
|
||||
{limitReached ? "Maximale Menge im Warenkorb" : added ? "Hinzugefügt ✓" : label}
|
||||
</span>
|
||||
<Image alt="" src="/icon-cart-outline.png" width={32} height={30} className="h-[1.875rem] w-8 object-contain" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user