Files
MotionWebStudio/components/CookieBanner.tsx

132 lines
4.9 KiB
TypeScript
Raw Permalink Normal View History

2025-12-21 20:40:32 +01:00
import React, { useState, useEffect } from 'react';
import { X, Check, Cookie } from 'lucide-react';
import { Link } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
import { supabase, isSupabaseConfigured } from '../lib/supabaseClient';
export const CookieBanner: React.FC = () => {
const { user } = useAuth();
const [isVisible, setIsVisible] = useState(false);
const [hasChecked, setHasChecked] = useState(false);
useEffect(() => {
const checkAndSyncConsent = async () => {
// 1. Check Local Storage choice
const localConsent = localStorage.getItem('cookie_consent');
// If a choice was already made locally, we hide the banner immediately
if (localConsent !== null) {
setIsVisible(false);
setHasChecked(true);
// AUTO-SYNC: If user is logged in, ensure the local choice is synced to the database
if (user && isSupabaseConfigured) {
try {
const consentValue = localConsent === 'true';
await supabase
.from('profiles')
.update({ cookie_consent: consentValue })
.eq('id', user.id);
} catch (e) {
console.error("Error auto-syncing cookie consent to DB:", e);
}
}
return;
}
// 2. If NO local choice but user IS logged in, try to fetch from DB
if (user && isSupabaseConfigured) {
try {
const { data, error } = await supabase
.from('profiles')
.select('cookie_consent')
.eq('id', user.id)
.maybeSingle();
if (!error && data && data.cookie_consent !== null) {
// Save DB choice to local storage and hide
localStorage.setItem('cookie_consent', data.cookie_consent.toString());
setIsVisible(false);
setHasChecked(true);
return;
}
} catch (e) {
console.error("Error checking cookie consent in DB:", e);
}
}
// 3. If NO choice found anywhere, show the banner
setIsVisible(true);
setHasChecked(true);
};
checkAndSyncConsent();
}, [user]);
const handleConsent = async (allowed: boolean) => {
// Save to local storage immediately to hide banner
localStorage.setItem('cookie_consent', allowed.toString());
setIsVisible(false);
// If logged in, also update the database
if (user && isSupabaseConfigured) {
try {
await supabase
.from('profiles')
.update({ cookie_consent: allowed })
.eq('id', user.id);
} catch (e) {
console.error("Error saving cookie consent to DB manually:", e);
}
}
// Trigger storage event for AnalyticsTracker and other listeners
window.dispatchEvent(new Event('storage'));
};
if (!isVisible || !hasChecked) return null;
return (
<div className="fixed bottom-6 right-6 z-[100] max-w-sm w-full animate-fade-in-up px-4 sm:px-0">
<div className="bg-white/95 backdrop-blur-md rounded-2xl shadow-[0_20px_50px_rgba(0,0,0,0.15)] border border-gray-100 p-6 flex flex-col gap-4">
<div className="flex items-start gap-4">
<div className="p-3 bg-primary/10 rounded-xl text-primary flex-shrink-0">
<Cookie className="w-6 h-6" />
</div>
<div className="flex-grow">
<h3 className="text-sm font-bold text-gray-900">Sütik és Adatvédelem</h3>
<p className="text-xs text-gray-500 mt-1 leading-relaxed">
Az élmény fokozása érdekében sütiket használunk. Az elfogadással hozzájárul az anonim látogatottsági adatok gyűjtéséhez.
</p>
</div>
<button
onClick={() => setIsVisible(false)}
className="text-gray-400 hover:text-gray-600 transition-colors p-1"
title="Bezárás"
>
<X className="w-4 h-4" />
</button>
</div>
<div className="flex gap-3">
<button
onClick={() => handleConsent(true)}
className="flex-1 bg-primary text-white py-2.5 px-4 rounded-xl text-xs font-bold hover:bg-primary-dark transition-all flex items-center justify-center gap-2 shadow-lg shadow-primary/20 hover:scale-[1.02] active:scale-95"
>
<Check className="w-3.5 h-3.5" /> Elfogadom
</button>
<button
onClick={() => handleConsent(false)}
className="flex-1 bg-gray-100 text-gray-600 py-2.5 px-4 rounded-xl text-xs font-bold hover:bg-gray-200 transition-all active:scale-95"
>
Elutasítom
</button>
</div>
<div className="text-[10px] text-center text-gray-400">
További információkért olvassa el az <Link to="/privacy" className="underline hover:text-primary transition-colors">Adatkezelési tájékoztatónkat</Link>.
</div>
</div>
</div>
);
};