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

107
src/app/settings/page.tsx Normal file
View File

@@ -0,0 +1,107 @@
import { redirect } from 'next/navigation';
import { createClient } from '@/lib/supabase/server';
import { getProfile } from '@/services/profile-actions';
import ProfileForm from '@/components/ProfileForm';
import PasswordChangeForm from '@/components/PasswordChangeForm';
import { ArrowLeft, Settings, Cookie, Shield } from 'lucide-react';
import Link from 'next/link';
export const metadata = {
title: 'Einstellungen',
};
export default async function SettingsPage() {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
redirect('/login');
}
const profile = await getProfile();
return (
<div className="min-h-screen bg-zinc-950">
{/* Header */}
<header className="sticky top-0 z-40 bg-zinc-950/80 backdrop-blur-lg border-b border-zinc-800">
<div className="max-w-2xl mx-auto px-4 py-4 flex items-center gap-4">
<Link
href="/"
className="p-2 -ml-2 text-zinc-400 hover:text-white transition-colors"
>
<ArrowLeft size={20} />
</Link>
<div className="flex items-center gap-2">
<Settings size={20} className="text-orange-500" />
<h1 className="text-lg font-bold text-white">Einstellungen</h1>
</div>
</div>
</header>
{/* Content */}
<main className="max-w-2xl mx-auto px-4 py-6 space-y-6">
{/* Profile Form */}
<ProfileForm
initialData={{
email: profile?.email,
display_name: profile?.display_name,
}}
/>
{/* Password Change Form */}
<PasswordChangeForm />
{/* Cookie Settings */}
<div className="bg-zinc-900 border border-zinc-800 rounded-2xl p-6">
<h2 className="text-lg font-bold text-white mb-4 flex items-center gap-2">
<Cookie size={20} className="text-orange-500" />
Cookie-Einstellungen
</h2>
<p className="text-sm text-zinc-400 mb-4">
Diese App verwendet nur technisch notwendige Cookies für die Authentifizierung und funktionale Cookies für UI-Präferenzen.
</p>
<div className="space-y-2 text-sm">
<div className="flex items-center gap-2 text-zinc-300">
<Shield size={14} className="text-green-500" />
<span><strong>Notwendig:</strong> Supabase Auth Cookies</span>
</div>
<div className="flex items-center gap-2 text-zinc-300">
<Shield size={14} className="text-blue-500" />
<span><strong>Funktional:</strong> Sprache, UI-Status</span>
</div>
</div>
</div>
{/* Data & Privacy */}
<div className="bg-zinc-900 border border-zinc-800 rounded-2xl p-6">
<h2 className="text-lg font-bold text-white mb-4 flex items-center gap-2">
<Shield size={20} className="text-orange-500" />
Datenschutz
</h2>
<div className="space-y-4">
<p className="text-sm text-zinc-400">
Deine Daten werden sicher auf EU-Servern gespeichert.
</p>
<Link
href="/privacy"
className="inline-block text-sm text-orange-500 hover:text-orange-400 underline"
>
Datenschutzerklärung lesen
</Link>
</div>
</div>
{/* Account info */}
<div className="bg-zinc-800/50 border border-zinc-700 rounded-2xl p-4 text-center">
<p className="text-xs text-zinc-500">
Mitglied seit: {new Date(profile?.created_at || '').toLocaleDateString('de-DE', {
day: '2-digit',
month: 'long',
year: 'numeric'
})}
</p>
</div>
</main>
</div>
);
}