Files
protekauto-frontend/src/components/CookieConsent.tsx

271 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import { CookiePreferences, initializeAnalytics, initializeMarketing } from '@/lib/cookie-utils';
interface CookieConsentProps {
onAccept?: () => void;
onDecline?: () => void;
onConfigure?: (preferences: CookiePreferences) => void;
}
const CookieConsent: React.FC<CookieConsentProps> = ({ onAccept, onDecline, onConfigure }) => {
const [isVisible, setIsVisible] = useState(false);
const [showDetails, setShowDetails] = useState(false);
const [preferences, setPreferences] = useState<CookiePreferences>({
necessary: true, // Всегда включены
analytics: false,
marketing: false,
functional: false,
});
useEffect(() => {
// Проверяем, есть ли уже согласие в localStorage
const cookieConsent = localStorage.getItem('cookieConsent');
if (!cookieConsent) {
setIsVisible(true);
}
}, []);
const handleAcceptAll = () => {
const allAccepted = {
necessary: true,
analytics: true,
marketing: true,
functional: true,
};
localStorage.setItem('cookieConsent', 'accepted');
localStorage.setItem('cookiePreferences', JSON.stringify(allAccepted));
// Инициализируем сервисы после согласия
initializeAnalytics();
initializeMarketing();
setIsVisible(false);
onAccept?.();
};
const handleDeclineAll = () => {
const onlyNecessary = {
necessary: true,
analytics: false,
marketing: false,
functional: false,
};
localStorage.setItem('cookieConsent', 'declined');
localStorage.setItem('cookiePreferences', JSON.stringify(onlyNecessary));
setIsVisible(false);
onDecline?.();
};
const handleSavePreferences = () => {
localStorage.setItem('cookieConsent', 'configured');
localStorage.setItem('cookiePreferences', JSON.stringify(preferences));
// Инициализируем сервисы согласно настройкам
if (preferences.analytics) {
initializeAnalytics();
}
if (preferences.marketing) {
initializeMarketing();
}
setIsVisible(false);
onConfigure?.(preferences);
};
const togglePreference = (key: keyof CookiePreferences) => {
if (key === 'necessary') return; // Необходимые cookies нельзя отключить
setPreferences(prev => ({
...prev,
[key]: !prev[key]
}));
};
if (!isVisible) return null;
return (
<div className="fixed bottom-0 left-0 right-0 z-50 bg-white border-t border-gray-200 shadow-lg cookie-consent-enter">
<div className="max-w-7xl mx-auto p-6 max-md:p-4">
{!showDetails ? (
// Основной вид
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
{/* Текст согласия */}
<div className="flex-1">
<div className="flex items-start gap-3">
{/* Иконка cookie */}
<div className="flex-shrink-0 mt-1">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" className="text-gray-600">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1.5 3.5c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm3 2c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm-6 1c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm2.5 3c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm4.5-1c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm-2 4c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm-3.5-2c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1z" fill="currentColor"/>
</svg>
</div>
<div>
<h3 className="text-lg font-semibold text-gray-950 mb-2">
Мы используем файлы cookie
</h3>
<p className="text-sm text-gray-600 leading-relaxed">
Наш сайт использует файлы cookie для улучшения работы сайта, персонализации контента и анализа трафика.
Продолжая использовать сайт, вы соглашаетесь с нашей{' '}
<a
href="/privacy-policy"
className="text-red-600 hover:text-red-700 underline"
target="_blank"
rel="noopener noreferrer"
>
политикой конфиденциальности
</a>
{' '}и использованием файлов cookie.
</p>
</div>
</div>
</div>
{/* Кнопки */}
<div className="flex flex-col sm:flex-row gap-3 md:flex-shrink-0">
<button
onClick={() => setShowDetails(true)}
className="px-6 py-3 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors duration-200 min-w-[120px]"
>
Настроить
</button>
<button
onClick={handleDeclineAll}
className="px-6 py-3 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors duration-200 min-w-[120px]"
>
Отклонить
</button>
<button
onClick={handleAcceptAll}
className="px-6 py-3 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-lg transition-colors duration-200 min-w-[120px]"
>
Принять все
</button>
</div>
</div>
) : (
// Детальный вид с настройками
<div className="space-y-6">
{/* Заголовок */}
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold text-gray-950">
Настройки файлов cookie
</h3>
<button
onClick={() => setShowDetails(false)}
className="text-gray-500 hover:text-gray-700 p-1"
>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path d="M15 5L5 15M5 5l10 10" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</button>
</div>
{/* Настройки cookies */}
<div className="space-y-4">
{/* Необходимые cookies */}
<div className="flex items-start justify-between p-4 bg-gray-50 rounded-lg">
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<h4 className="font-medium text-gray-950">Необходимые cookies</h4>
<span className="text-xs px-2 py-1 bg-gray-200 text-gray-600 rounded">Обязательные</span>
</div>
<p className="text-sm text-gray-600">
Эти файлы cookie необходимы для работы сайта и не могут быть отключены.
</p>
</div>
<div className="flex-shrink-0 ml-4">
<div className="w-12 h-6 bg-red-600 rounded-full flex items-center justify-end px-1">
<div className="w-4 h-4 bg-white rounded-full"></div>
</div>
</div>
</div>
{/* Аналитические cookies */}
<div className="flex items-start justify-between p-4 bg-gray-50 rounded-lg">
<div className="flex-1">
<h4 className="font-medium text-gray-950 mb-2">Аналитические cookies</h4>
<p className="text-sm text-gray-600">
Помогают нам понять, как посетители взаимодействуют с сайтом.
</p>
</div>
<div className="flex-shrink-0 ml-4">
<button
onClick={() => togglePreference('analytics')}
className={`w-12 h-6 rounded-full flex items-center transition-colors duration-200 ${
preferences.analytics ? 'bg-red-600 justify-end' : 'bg-gray-300 justify-start'
} px-1`}
>
<div className="w-4 h-4 bg-white rounded-full"></div>
</button>
</div>
</div>
{/* Маркетинговые cookies */}
<div className="flex items-start justify-between p-4 bg-gray-50 rounded-lg">
<div className="flex-1">
<h4 className="font-medium text-gray-950 mb-2">Маркетинговые cookies</h4>
<p className="text-sm text-gray-600">
Используются для отслеживания посетителей и показа релевантной рекламы.
</p>
</div>
<div className="flex-shrink-0 ml-4">
<button
onClick={() => togglePreference('marketing')}
className={`w-12 h-6 rounded-full flex items-center transition-colors duration-200 ${
preferences.marketing ? 'bg-red-600 justify-end' : 'bg-gray-300 justify-start'
} px-1`}
>
<div className="w-4 h-4 bg-white rounded-full"></div>
</button>
</div>
</div>
{/* Функциональные cookies */}
<div className="flex items-start justify-between p-4 bg-gray-50 rounded-lg">
<div className="flex-1">
<h4 className="font-medium text-gray-950 mb-2">Функциональные cookies</h4>
<p className="text-sm text-gray-600">
Обеспечивают расширенную функциональность и персонализацию.
</p>
</div>
<div className="flex-shrink-0 ml-4">
<button
onClick={() => togglePreference('functional')}
className={`w-12 h-6 rounded-full flex items-center transition-colors duration-200 ${
preferences.functional ? 'bg-red-600 justify-end' : 'bg-gray-300 justify-start'
} px-1`}
>
<div className="w-4 h-4 bg-white rounded-full"></div>
</button>
</div>
</div>
</div>
{/* Кнопки действий */}
<div className="flex flex-col sm:flex-row gap-3 pt-4 border-t border-gray-200">
<button
onClick={handleDeclineAll}
className="px-6 py-3 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors duration-200 flex-1 sm:flex-initial min-w-[120px]"
>
Только необходимые
</button>
<button
onClick={handleSavePreferences}
className="px-6 py-3 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-lg transition-colors duration-200 flex-1 sm:flex-initial min-w-[120px]"
>
Сохранить настройки
</button>
<button
onClick={handleAcceptAll}
className="px-6 py-3 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-lg transition-colors duration-200 flex-1 sm:flex-initial min-w-[120px]"
>
Принять все
</button>
</div>
</div>
)}
</div>
</div>
);
};
export default CookieConsent;