Add CookieConsentBanner component and integrate into layout.tsx for cookie consent management

This commit is contained in:
2025-06-26 10:30:49 +09:00
parent ab3a7c5bf9
commit cdac942fca
2 changed files with 130 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import "./globals.css";
import Navbar from "@/components/Navbar"; import Navbar from "@/components/Navbar";
import React from "react"; import React from "react";
import Footer from "@/components/Footer"; import Footer from "@/components/Footer";
import CookieConsentBanner from "@/components/CookieConsentBanner";
const geistSans = Geist({ const geistSans = Geist({
variable: "--font-geist-sans", variable: "--font-geist-sans",
@@ -59,6 +60,7 @@ export default function RootLayout({
<Navbar/> <Navbar/>
{children} {children}
<Footer/> <Footer/>
<CookieConsentBanner/>
</body> </body>
</html> </html>
); );

View File

@@ -0,0 +1,128 @@
// CookieConsentBanner.tsx
'use client';
import {useEffect, useState} from 'react';
export default function CookieConsentBanner() {
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
const [stats, setStats] = useState(false);
const [personalization, setPersonalization] = useState(false);
useEffect(() => {
const consent = localStorage.getItem('cookie_consent');
if (!consent) setVisible(true);
const show = () => {
setVisible(true);
};
window.addEventListener('show-cookie-banner', show);
return () => window.removeEventListener('show-cookie-banner', show);
}, []);
const handleAccept = () => {
setLoading(true);
setTimeout(() => {
localStorage.setItem('cookie_consent', 'true');
localStorage.setItem('cookie_stats', stats.toString());
localStorage.setItem('cookie_personalization', personalization.toString());
setVisible(false);
setLoading(false);
}, 1000);
};
const handleAcceptAll = () => {
setLoading(true);
setStats(true);
setPersonalization(true);
setTimeout(() => {
localStorage.setItem('cookie_consent', 'true');
localStorage.setItem('cookie_stats', 'true');
localStorage.setItem('cookie_personalization', 'true');
setVisible(false);
setLoading(false);
}, 1000);
};
const handleDecline = () => {
localStorage.setItem('cookie_consent', 'false');
localStorage.setItem('cookie_stats', 'false');
localStorage.setItem('cookie_personalization', 'false');
setVisible(false);
};
return visible ? (
<div className="fixed inset-0 z-50 bg-black/50 flex items-center justify-center px-4">
<div className="bg-white max-w-2xl w-full rounded-xl shadow-lg overflow-hidden text-sm text-gray-800">
<div className="px-6 py-4 border-b border-gray-200">
<h2 className="text-lg font-semibold">Wir nutzen Cookies und andere Technologien.</h2>
</div>
<div className="px-6 py-4 space-y-4 max-h-[60vh] overflow-y-auto">
<p>
Diese Website nutzt Cookies und vergleichbare Funktionen zur Verarbeitung von
Endgeräteinformationen und personenbezogenen Daten. Die Verarbeitung dient der Einbindung von
Inhalten, externen Diensten und Elementen Dritter, der statistischen Analyse/Messung, der
personalisierten Werbung sowie der Einbindung sozialer Medien.
</p>
<p>
Je nach Funktion werden dabei Daten an Dritte weitergegeben und in Länder außerhalb der EU
übertragen, in denen kein angemessenes Datenschutzniveau besteht z. B. die USA. Ihre
Einwilligung ist freiwillig und kann jederzeit über das Symbol unten links widerrufen werden.
</p>
<div className="space-y-2">
<label className="block">
<input type="checkbox" defaultChecked disabled className="mr-2"/>
Notwendige Cookies (immer aktiv)
</label>
<label className="block">
<input
type="checkbox"
checked={stats}
onChange={(e) => setStats(e.target.checked)}
className="mr-2"
/>
Statistiken (z. B. Besuchertracking)
</label>
<label className="block">
<input
type="checkbox"
checked={personalization}
onChange={(e) => setPersonalization(e.target.checked)}
className="mr-2"
/>
Personalisierung (z. B. eingebettete Medien, Google Maps)
</label>
</div>
</div>
<div className="px-6 py-4 border-t border-gray-200 flex flex-col sm:flex-row sm:justify-end gap-2">
<div className="flex flex-wrap gap-2">
<button
onClick={handleDecline}
className="px-4 py-2 border rounded text-gray-600 hover:bg-gray-100"
>
Ablehnen
</button>
<button
onClick={handleAccept}
className="px-4 py-2 border rounded text-gray-700 hover:bg-gray-100 disabled:opacity-60"
disabled={loading}
>
{loading ? 'Speichere ...' : 'Akzeptieren'}
</button>
<button
onClick={handleAcceptAll}
className="px-4 py-2 bg-red-700 text-white rounded hover:bg-red-800 disabled:opacity-60"
disabled={loading}
>
{loading ? 'Speichere ...' : 'Alles akzeptieren'}
</button>
</div>
</div>
<div className="px-6 py-3 border-t border-gray-100 text-xs text-gray-500 flex justify-start gap-4">
<a href="/impressum" className="hover:underline">Impressum</a>
<a href="/datenschutz" className="hover:underline">Datenschutzerklärung</a>
</div>
</div>
</div>
) : null;
}