From ac6c3d6b7196f93e11f6db13d79c9deb8f04b7dd Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 1 Aug 2026 21:58:19 +0000 Subject: [PATCH] =?UTF-8?q?Add=20GoogleMapsEmbed.tsx=20=E2=80=94=20consent?= =?UTF-8?q?-gated=20Maps=20embed,=20prepared=20but=20unused?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uses Klaro's own built-in contextual-consent mechanism (not loadTrackingCode.ts's script-injection path) — the iframe renders with data-name="google-maps" and its real src; Klaro's DOM scan finds it after mount and blanks/restores src based on that service's consent state, showing its own placeholder (styled via KlaroConsentManager.tsx's KlaroTheme) in the meantime. No map embedded anywhere in the app yet — this is prep work only, per explicit request ahead of an actual page needing one. Co-Authored-By: Claude Sonnet 5 --- README.md | 25 +++++++++++++++ app/components/GoogleMapsEmbed.tsx | 44 ++++++++++++++++++++++++++ app/components/KlaroConsentManager.tsx | 24 ++++++++++++++ app/lib/klaroConfig.ts | 21 ++++++++++++ app/lib/loadTrackingCode.ts | 6 ++++ app/lib/payload.ts | 4 +-- 6 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 app/components/GoogleMapsEmbed.tsx diff --git a/README.md b/README.md index 4842263..5db54da 100644 --- a/README.md +++ b/README.md @@ -1854,6 +1854,31 @@ has its own dedicated Live Preview renderer, not the shared generic order-status one — there's no order for this email type, so no fake "Bestellnummer" line; CTA is "Zum Produkt", not "Bestellung ansehen". +## Google Maps (consent-gated embed, prepared but unused) + +No map is embedded anywhere in this app yet — `GoogleMapsEmbed.tsx` +exists as ready-to-use prep work. Unlike GA/Facebook Pixel/GTM (scripts +this app injects itself, see the tracking-codes section above), an +embedded iframe is gated by **Klaro's own built-in contextual-consent +mechanism**, not `loadTrackingCode.ts`: the iframe renders with its real +`src` and a `data-name="google-maps"` attribute; Klaro's DOM scan +(`renderContextualConsentNotices`, runs as part of `Klaro.render()`) +finds it after mount, blanks `src` and swaps in its own "Karte laden?" +placeholder (styled to match this site via `KlaroConsentManager.tsx`'s +`KlaroTheme`) until that service's consent is granted, then restores the +real `src`. `loadTrackingCode.ts`'s `google-maps` case is a deliberate +no-op — there's nothing to inject, Klaro handles the swap entirely on its +own. + +Backend prerequisite: exactly one `tracking-codes` row with +`provider: google-maps` must exist and be `active` (see the Payload +README) — `klaroConfig.ts`'s `serviceName()` special-cases this provider +to the fixed name `"google-maps"` (not id-based like every other +provider) since there's no distinguishing ID the way GA/FB/GTM each have +one; a second `google-maps` row would collide on that name. To actually +use it: `` +anywhere. + ## Product image gallery `ProductGallery.tsx` — main image + thumbnail strip, swappable on click, diff --git a/app/components/GoogleMapsEmbed.tsx b/app/components/GoogleMapsEmbed.tsx new file mode 100644 index 0000000..348e756 --- /dev/null +++ b/app/components/GoogleMapsEmbed.tsx @@ -0,0 +1,44 @@ +// Server Component — no "use client" needed. The consent gating itself +// happens entirely client-side inside Klaro (KlaroConsentManager.tsx), +// not via any React state here: Klaro's own contextual-consent DOM scan +// (renderContextualConsentNotices, runs as part of Klaro.render()) finds +// this iframe by its `data-name="google-maps"` attribute after mount, +// blanks its `src` and inserts its own "Karte laden?" placeholder in +// front of it until that service's consent is granted, then restores the +// real `src`. See klaroConfig.ts's own comment on the "google-maps" +// service this depends on — a `tracking-codes` row with that provider +// must exist and be `active`, or Klaro never gates (and never un-blanks) +// this iframe at all. +// +// `width`/`height` are real HTML attributes, not just the Tailwind aspect- +// ratio wrapper below — Klaro reads `element.width`/`element.height` (the +// DOM attributes) to size its own placeholder box before the real iframe +// has rendered, so both need to be present even though the wrapper's +// `aspect-[...]` class is what actually controls layout. +export function GoogleMapsEmbed({ + src, + title, + className, +}: { + /** A full Google Maps embed URL (Google Maps → Teilen → Karte einbetten + * → "HTML kopieren" → the `src` attribute of that iframe), e.g. + * "https://www.google.com/maps/embed?pb=...". */ + src: string; + title: string; + className?: string; +}) { + return ( +
+