feat: Add EU cookie banner and user settings page

Cookie Banner:
- GDPR-compliant consent banner
- Shows on first visit, stores consent in localStorage
- Two options: Accept All / Only Essential
- Dark theme with smooth animations

Settings Page (/settings):
- Profile form: display name editing
- Password change with validation
- Cookie settings info section
- Privacy links and account info

New files:
- src/hooks/useCookieConsent.ts
- src/components/CookieBanner.tsx
- src/components/ProfileForm.tsx
- src/components/PasswordChangeForm.tsx
- src/services/profile-actions.ts
- src/app/settings/page.tsx
This commit is contained in:
2025-12-26 21:30:00 +01:00
parent 9c5f538efb
commit 6c37481d17
8 changed files with 692 additions and 1 deletions

View File

@@ -0,0 +1,69 @@
'use client';
import { useState, useEffect, useCallback } from 'react';
export type ConsentLevel = 'all' | 'essential' | null;
interface CookieConsent {
level: ConsentLevel;
timestamp: string;
}
const CONSENT_KEY = 'cookie_consent';
/**
* Hook for managing GDPR-compliant cookie consent
*/
export function useCookieConsent() {
const [consent, setConsent] = useState<CookieConsent | null>(null);
const [isLoading, setIsLoading] = useState(true);
// Load consent from localStorage on mount
useEffect(() => {
try {
const stored = localStorage.getItem(CONSENT_KEY);
if (stored) {
setConsent(JSON.parse(stored));
}
} catch (e) {
console.warn('[CookieConsent] Failed to load consent:', e);
}
setIsLoading(false);
}, []);
// Accept all cookies (essential + functional)
const acceptAll = useCallback(() => {
const newConsent: CookieConsent = {
level: 'all',
timestamp: new Date().toISOString(),
};
localStorage.setItem(CONSENT_KEY, JSON.stringify(newConsent));
setConsent(newConsent);
}, []);
// Accept only essential cookies
const acceptEssential = useCallback(() => {
const newConsent: CookieConsent = {
level: 'essential',
timestamp: new Date().toISOString(),
};
localStorage.setItem(CONSENT_KEY, JSON.stringify(newConsent));
setConsent(newConsent);
}, []);
// Reset consent (for settings page)
const resetConsent = useCallback(() => {
localStorage.removeItem(CONSENT_KEY);
setConsent(null);
}, []);
return {
hasConsent: consent !== null,
consentLevel: consent?.level ?? null,
consentTimestamp: consent?.timestamp ?? null,
isLoading,
acceptAll,
acceptEssential,
resetConsent,
};
}