mirror of
https://github.com/Motion-Games/MotionWebStudio.git
synced 2026-04-21 09:00:53 +02:00
132 lines
4.9 KiB
TypeScript
132 lines
4.9 KiB
TypeScript
|
|
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>
|
||
|
|
);
|
||
|
|
};
|