537543bf91
Swaps the hand-rolled CookieBanner.tsx/useConsent.ts/TrackingScripts.tsx for kiprotect/klaro — brings a real per-service consent list and bundled German UI translations that a custom implementation would have had to build from scratch (per user feedback that a proper CMP is worth it over a purely custom binary accept/reject banner). klaroConfig.ts builds Klaro's config dynamically from the existing tracking-codes backend collection (one Klaro "service" per row, grouped by consentCategory as its purpose). loadTrackingCode.ts is the actual script-injection side effect, wired in via each service's `callback(consent)` — same GA4/Facebook-Pixel/GTM/custom loader logic TrackingScripts.tsx had, just triggered imperatively instead of declaratively rendered. Brand color applied via Klaro's CSS custom property overrides (styling.green1 etc.), not custom SCSS. No @types/klaro package exists — types/klaro.d.ts declares only the small surface actually used. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
76 lines
3.0 KiB
TypeScript
76 lines
3.0 KiB
TypeScript
import type { TrackingCode } from "./payload";
|
|
|
|
// Imperative <script> injection, not next/script — this fires from
|
|
// KlaroConsentManager.tsx's per-service `callback(consent)`, i.e. at an
|
|
// arbitrary point after mount (whenever a visitor actually accepts), not
|
|
// declaratively on every render. Idempotent via the DOM id check, since
|
|
// Klaro's `onlyOnce: true` (see klaroConfig.ts) already tries to guarantee
|
|
// a single callback-with-consent-true per page load, but this is a cheap
|
|
// second guard against ever injecting the same script twice.
|
|
function injectScript(id: string, src?: string, inlineJs?: string) {
|
|
if (document.getElementById(id)) return;
|
|
const script = document.createElement("script");
|
|
script.id = id;
|
|
script.async = true;
|
|
if (src) script.src = src;
|
|
else script.textContent = inlineJs ?? "";
|
|
document.head.appendChild(script);
|
|
}
|
|
|
|
// One loader per TrackingCodes.provider (google-analytics/facebook-pixel/
|
|
// google-tag-manager/other) — same fixed loader snippets per provider as
|
|
// the Payload backend's own admin.description promises, 'other' is the
|
|
// only one whose content is admin-supplied rather than a fixed snippet
|
|
// (trusted deliberately, see TrackingCodes.ts on the backend).
|
|
export function loadTrackingCode(code: TrackingCode): void {
|
|
const baseId = `tracking-code-${code.id}`;
|
|
|
|
if (code.provider === "google-analytics" && code.measurementId) {
|
|
injectScript(`${baseId}-loader`, `https://www.googletagmanager.com/gtag/js?id=${code.measurementId}`);
|
|
injectScript(
|
|
`${baseId}-init`,
|
|
undefined,
|
|
`window.dataLayer = window.dataLayer || [];
|
|
function gtag(){dataLayer.push(arguments);}
|
|
gtag('js', new Date());
|
|
gtag('config', '${code.measurementId}');`,
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (code.provider === "facebook-pixel" && code.pixelId) {
|
|
injectScript(
|
|
baseId,
|
|
undefined,
|
|
`!function(f,b,e,v,n,t,s)
|
|
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
|
|
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
|
|
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
|
|
n.queue=[];t=b.createElement(e);t.async=!0;
|
|
t.src=v;s=b.getElementsByTagName(e)[0];
|
|
s.parentNode.insertBefore(t,s)}(window, document,'script',
|
|
'https://connect.facebook.net/en_US/fbevents.js');
|
|
fbq('init', '${code.pixelId}');
|
|
fbq('track', 'PageView');`,
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (code.provider === "google-tag-manager" && code.containerId) {
|
|
injectScript(
|
|
baseId,
|
|
undefined,
|
|
`(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
|
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
|
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
|
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
|
})(window,document,'script','dataLayer','${code.containerId}');`,
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (code.provider === "other" && code.customScript) {
|
|
injectScript(baseId, undefined, code.customScript);
|
|
}
|
|
}
|