Implement cookie consent banner and integrate Google Consent API

Integrate Google Consent Management Platform (CMP) and a custom cookie consent banner component to manage user privacy preferences, including consent for analytics and advertising cookies.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 2cd2c0bc-434c-4bc9-ad3f-b99d3897a0d1
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/2cd2c0bc-434c-4bc9-ad3f-b99d3897a0d1/gjpMN2A
This commit is contained in:
sebastjanartic 2025-09-03 20:42:01 +00:00
parent d40cabef2d
commit b9b89c6025
5 changed files with 259 additions and 1 deletions

View File

@ -40,4 +40,4 @@ args = "npm run dev"
waitForPort = 5000
[agent]
integrations = ["javascript_google_analytics==1.0.0", "javascript_database==1.0.0"]
integrations = ["javascript_database==1.0.0", "javascript_google_analytics==1.0.0"]

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -4,6 +4,20 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no, viewport-fit=cover" />
<title>go4.video Top-Inhalte von Folx TV</title>
<!-- Google Consent Management Platform -->
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied'
});
</script>
<script async src="https://fundingchoicesmessages.google.com/i/pub-4465464714854276?ers=1" nonce="temp-nonce"></script>
<script nonce="temp-nonce">(function() {function signalGooglefcPresent() {if (!window.frames['googlefcPresent']) {if (document.body) {const iframe = document.createElement('iframe'); iframe.style = 'width: 0; height: 0; border: none; z-index: -1000; left: -1000px; top: -1000px;'; iframe.style.display = 'none'; iframe.name = 'googlefcPresent'; document.body.appendChild(iframe);} else {setTimeout(signalGooglefcPresent, 0);}}}signalGooglefcPresent();})();</script>
<meta name="description" content="Video-Welt von Folx TV immer bei dir" />
<!-- Google Search Console verification -->

View File

@ -3,6 +3,7 @@ import { queryClient } from "./lib/queryClient";
import { QueryClientProvider } from "@tanstack/react-query";
import { Toaster } from "@/components/ui/toaster";
import { TooltipProvider } from "@/components/ui/tooltip";
import CookieConsent from "@/components/CookieConsent";
import Home from "@/pages/home";
import VideoPage from "@/pages/VideoPage";
import FolxStadlPage from "@/pages/FolxStadlPage";
@ -36,6 +37,7 @@ function App() {
<QueryClientProvider client={queryClient}>
<TooltipProvider>
<Toaster />
<CookieConsent />
<Router />
</TooltipProvider>
</QueryClientProvider>

View File

@ -0,0 +1,242 @@
import { useState, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import { X } from 'lucide-react';
interface ConsentState {
necessary: boolean;
analytics: boolean;
advertising: boolean;
}
export default function CookieConsent() {
const [showBanner, setShowBanner] = useState(false);
const [showDetails, setShowDetails] = useState(false);
const [consent, setConsent] = useState<ConsentState>({
necessary: true,
analytics: false,
advertising: false
});
useEffect(() => {
// Check if user has already made a choice
const hasConsented = localStorage.getItem('cookie_consent');
if (!hasConsented) {
setShowBanner(true);
} else {
// Load existing consent
const savedConsent = JSON.parse(hasConsented);
setConsent(savedConsent);
updateGoogleConsent(savedConsent);
}
}, []);
const updateGoogleConsent = (consentState: ConsentState) => {
if (window.gtag) {
window.gtag('consent', 'update', {
'ad_storage': consentState.advertising ? 'granted' : 'denied',
'analytics_storage': consentState.analytics ? 'granted' : 'denied',
'ad_user_data': consentState.advertising ? 'granted' : 'denied',
'ad_personalization': consentState.advertising ? 'granted' : 'denied'
});
}
};
const handleAcceptAll = () => {
const newConsent = {
necessary: true,
analytics: true,
advertising: true
};
setConsent(newConsent);
updateGoogleConsent(newConsent);
localStorage.setItem('cookie_consent', JSON.stringify(newConsent));
setShowBanner(false);
setShowDetails(false);
};
const handleRejectAll = () => {
const newConsent = {
necessary: true,
analytics: false,
advertising: false
};
setConsent(newConsent);
updateGoogleConsent(newConsent);
localStorage.setItem('cookie_consent', JSON.stringify(newConsent));
setShowBanner(false);
setShowDetails(false);
};
const handleSavePreferences = () => {
updateGoogleConsent(consent);
localStorage.setItem('cookie_consent', JSON.stringify(consent));
setShowBanner(false);
setShowDetails(false);
};
const handleConsentChange = (key: keyof ConsentState, value: boolean) => {
if (key === 'necessary') return; // Cannot disable necessary cookies
setConsent(prev => ({ ...prev, [key]: value }));
};
if (!showBanner) return null;
return (
<div className="fixed inset-0 z-[9999] flex items-end justify-center p-4 pointer-events-none">
<div className="w-full max-w-4xl pointer-events-auto">
<div className="bg-bunny-dark border border-white/20 rounded-lg shadow-2xl">
{!showDetails ? (
// Simple banner
<div className="p-6">
<div className="flex items-start justify-between mb-4">
<div className="flex items-center space-x-2">
<div className="w-6 h-6 bg-gradient-to-r from-purple-600 to-blue-500 rounded-lg flex items-center justify-center">
<div className="w-0 h-0 border-l-[6px] border-l-white border-y-[4px] border-y-transparent ml-0.5"></div>
</div>
<h3 className="text-lg font-semibold text-white">Cookie-Einstellungen</h3>
</div>
<button
onClick={() => setShowBanner(false)}
className="text-bunny-muted hover:text-white transition-colors"
>
<X className="w-5 h-5" />
</button>
</div>
<p className="text-bunny-light text-sm mb-4">
Wir verwenden Cookies und ähnliche Technologien, um unsere Website zu verbessern,
Inhalte zu personalisieren und Werbung zu schalten. Durch das Fortsetzen der Nutzung
unserer Website stimmen Sie der Verwendung von Cookies zu.
</p>
<div className="flex flex-col sm:flex-row gap-3">
<Button
onClick={handleAcceptAll}
className="gradient-primary text-white border-none hover:opacity-90 transition-opacity"
>
Alle akzeptieren
</Button>
<Button
onClick={handleRejectAll}
variant="outline"
className="border-white/20 text-white hover:bg-white/10"
>
Alle ablehnen
</Button>
<Button
onClick={() => setShowDetails(true)}
variant="ghost"
className="text-bunny-blue hover:text-purple-400 hover:bg-transparent"
>
Einstellungen verwalten
</Button>
</div>
</div>
) : (
// Detailed settings
<div className="p-6">
<div className="flex items-start justify-between mb-6">
<h3 className="text-xl font-semibold text-white">Cookie-Einstellungen</h3>
<button
onClick={() => setShowDetails(false)}
className="text-bunny-muted hover:text-white transition-colors"
>
<X className="w-5 h-5" />
</button>
</div>
<div className="space-y-6 mb-6">
{/* Necessary Cookies */}
<div className="bg-bunny-gray/20 p-4 rounded-lg">
<div className="flex items-center justify-between mb-2">
<h4 className="text-white font-medium">Notwendige Cookies</h4>
<div className="bg-bunny-blue/20 text-bunny-blue px-2 py-1 rounded text-xs">
Immer aktiv
</div>
</div>
<p className="text-bunny-light text-sm">
Diese Cookies sind für das Funktionieren der Website erforderlich und können
in unseren Systemen nicht deaktiviert werden.
</p>
</div>
{/* Analytics Cookies */}
<div className="bg-bunny-gray/20 p-4 rounded-lg">
<div className="flex items-center justify-between mb-2">
<h4 className="text-white font-medium">Analyse-Cookies</h4>
<label className="relative inline-flex items-center cursor-pointer">
<input
type="checkbox"
checked={consent.analytics}
onChange={(e) => handleConsentChange('analytics', e.target.checked)}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-bunny-gray peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bunny-blue"></div>
</label>
</div>
<p className="text-bunny-light text-sm">
Diese Cookies ermöglichen es uns, Besuche und Verkehrsquellen zu zählen,
damit wir die Leistung unserer Website messen und verbessern können.
</p>
</div>
{/* Advertising Cookies */}
<div className="bg-bunny-gray/20 p-4 rounded-lg">
<div className="flex items-center justify-between mb-2">
<h4 className="text-white font-medium">Werbe-Cookies</h4>
<label className="relative inline-flex items-center cursor-pointer">
<input
type="checkbox"
checked={consent.advertising}
onChange={(e) => handleConsentChange('advertising', e.target.checked)}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-bunny-gray peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bunny-blue"></div>
</label>
</div>
<p className="text-bunny-light text-sm">
Diese Cookies werden von Werbepartnern über unsere Website gesetzt. Sie können
verwendet werden, um ein Profil Ihrer Interessen zu erstellen und relevante
Werbung auf anderen Websites zu zeigen.
</p>
</div>
</div>
<div className="flex flex-col sm:flex-row gap-3">
<Button
onClick={handleSavePreferences}
className="gradient-primary text-white border-none hover:opacity-90 transition-opacity"
>
Einstellungen speichern
</Button>
<Button
onClick={handleAcceptAll}
variant="outline"
className="border-white/20 text-white hover:bg-white/10"
>
Alle akzeptieren
</Button>
<Button
onClick={handleRejectAll}
variant="ghost"
className="text-bunny-muted hover:text-white hover:bg-white/5"
>
Alle ablehnen
</Button>
</div>
</div>
)}
</div>
</div>
</div>
);
}
// Global declaration for gtag
declare global {
interface Window {
gtag: (...args: any[]) => void;
}
}