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:
Marco
2026-08-01 20:03:11 +00:00
parent c6b12e9d60
commit 70ee518e1d
8 changed files with 327 additions and 75 deletions
+35
View File
@@ -1169,3 +1169,38 @@ export async function getSeoSettings(): Promise<SeoSettings> {
(typeof doc.seoDefaultOgImage === "object" && doc.seoDefaultOgImage?.url) || SEO_SETTINGS_FALLBACK.defaultOgImage,
};
}
export type TrackingCode = {
id: number;
provider: "google-analytics" | "facebook-pixel" | "google-tag-manager" | "other";
consentCategory: "necessary" | "analytics" | "marketing";
measurementId: string | null;
pixelId: string | null;
containerId: string | null;
customScript: string | null;
};
// Public read (TrackingCodes.ts's own access.read: () => true), unlike
// most of this file's other Company-Settings-adjacent fetchers — no
// x-order-service-secret header needed. Only `active: true` rows, since
// TrackingScripts.tsx has no reason to even know an inactive one exists.
// Consent-gating itself happens in TrackingScripts.tsx, not here — this
// fetcher runs server-side (no cookie access), the gating decision is a
// client-only concern (useConsent()).
export async function getTrackingCodes(): Promise<TrackingCode[]> {
const params = new URLSearchParams({
"where[tenant.slug][equals]": TENANT_SLUG,
"where[active][equals]": "true",
depth: "0",
limit: "50",
});
const res = await fetch(`${PAYLOAD_URL}/api/tracking-codes?${params}`, {
next: { revalidate: 60 },
});
if (!res.ok) {
console.error(`getTrackingCodes: Payload returned ${res.status} ${res.statusText}`);
return [];
}
const data: { docs?: TrackingCode[] } = await res.json();
return Array.isArray(data.docs) ? data.docs : [];
}