ac6c3d6b71
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 <noreply@anthropic.com>
82 lines
3.3 KiB
TypeScript
82 lines
3.3 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 {
|
|
// No-op — Google Maps isn't a script this app injects. Klaro's own
|
|
// contextual-consent DOM scan handles any `data-name="google-maps"`
|
|
// iframe (GoogleMapsEmbed.tsx) independently, purely off the service's
|
|
// consent state — see klaroConfig.ts's own comment on this service.
|
|
if (code.provider === "google-maps") return;
|
|
|
|
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);
|
|
}
|
|
}
|