feat(compliance): add GDPR/RODO compliant cookie consent banner

Implemented cookie consent banner to comply with EU regulations (GDPR/RODO).
The banner appears on first visit and stores user preference in localStorage.

Features:
- Non-intrusive bottom banner with clear messaging
- Accept/Decline options for user choice
- Link to privacy policy in About Us page
- Responsive design for mobile and desktop
- Auto-dismisses after consent with 1s delay on first show
- High z-index to stay above all content

Also added comprehensive Privacy & Cookies section to About Us page
explaining:
- What cookies we use (essential, analytics, preferences)
- How we handle user data
- GDPR/RODO compliance statements
- Contact information for privacy questions

Changes:
- Created CookieConsent component with modern UI
- Integrated banner into App.jsx
- Updated about-us.md with privacy policy section
This commit is contained in:
Radosław Gierwiało
2025-12-05 22:22:23 +01:00
parent 2cab8c3eba
commit 3523172ecb
3 changed files with 117 additions and 4 deletions

View File

@@ -0,0 +1,85 @@
import { useState, useEffect } from 'react';
import { Cookie, X } from 'lucide-react';
/**
* GDPR/RODO compliant cookie consent banner
* Shows at bottom of screen on first visit, stores consent in localStorage
*/
const CookieConsent = () => {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
// Check if user has already consented
const hasConsented = localStorage.getItem('cookieConsent');
if (!hasConsented) {
// Show banner after a short delay for better UX
setTimeout(() => setIsVisible(true), 1000);
}
}, []);
const handleAccept = () => {
localStorage.setItem('cookieConsent', 'accepted');
setIsVisible(false);
};
const handleDecline = () => {
localStorage.setItem('cookieConsent', 'declined');
setIsVisible(false);
};
if (!isVisible) return null;
return (
<div className="fixed bottom-0 left-0 right-0 z-[9999] p-4 bg-gradient-to-t from-black/10 to-transparent pointer-events-none">
<div className="max-w-7xl mx-auto pointer-events-auto">
<div className="bg-white rounded-lg shadow-2xl border border-gray-200 p-4 sm:p-6">
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4">
{/* Icon */}
<div className="flex-shrink-0">
<div className="w-12 h-12 bg-primary-100 rounded-full flex items-center justify-center">
<Cookie className="w-6 h-6 text-primary-600" />
</div>
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<h3 className="text-lg font-semibold text-gray-900 mb-1">
We use cookies
</h3>
<p className="text-sm text-gray-600">
We use cookies and similar technologies to enhance your experience, analyze site traffic,
and for authentication purposes. By clicking "Accept", you consent to our use of cookies.{' '}
<a
href="/about-us"
className="text-primary-600 hover:text-primary-700 underline"
target="_blank"
rel="noopener noreferrer"
>
Learn more
</a>
</p>
</div>
{/* Actions */}
<div className="flex items-center gap-2 flex-shrink-0 w-full sm:w-auto">
<button
onClick={handleDecline}
className="flex-1 sm:flex-none px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
>
Decline
</button>
<button
onClick={handleAccept}
className="flex-1 sm:flex-none px-4 py-2 text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 rounded-lg transition-colors"
>
Accept
</button>
</div>
</div>
</div>
</div>
</div>
);
};
export default CookieConsent;