veza/apps/web/src/components/settings/account/AccountSettings.tsx
senke 6974c12a25 aesthetic-improvements: align spacing to 8px grid (Action 11.2.1.3)
- Created automated script (scripts/align-8px-grid.py) to align all spacing to 8px grid
- Replaced non-8px-aligned spacing: gap-3/p-3/m-3 (12px) → gap-4/p-4/m-4 (16px), gap-5/p-5/m-5 (20px) → gap-6/p-6/m-6 (24px), gap-10/p-10/m-10 (40px) → gap-12/p-12/m-12 (48px), gap-20/p-20/m-20 (80px) → gap-24/p-24/m-24 (96px)
- Preserved: 4px values (gap-1, p-1, m-1) as they may be intentional fine-tuning, responsive breakpoints (sm:, md:, lg:), test files, documentation
- Modified files across all components to ensure consistent 8px grid alignment
- Action 11.2.1.3: Align all elements to 8px grid - COMPLETE
2026-01-16 11:50:46 +01:00

280 lines
9.9 KiB
TypeScript

import React, { useState } from 'react';
import { Card } from '../../ui/card';
import { Button } from '../../ui/button';
import { useTheme } from '../../../context/ThemeContext';
import { ThemeVariant } from '../../../types';
import {
Mail,
User,
Globe,
Bell,
Lock,
ShieldAlert,
Monitor,
Moon,
Sun,
Laptop,
} from 'lucide-react';
import { ChangeEmailModal } from './ChangeEmailModal';
import { ChangeUsernameModal } from './ChangeUsernameModal';
import { DeleteAccountView } from './DeleteAccountView';
import { useToast } from '../../../context/ToastContext';
import { Switch } from '../../ui/switch';
export const AccountSettings: React.FC = () => {
const { theme, setTheme } = useTheme();
const { addToast } = useToast();
// State for sub-views and modals
const [view, setView] = useState<'main' | 'delete'>('main');
const [showEmailModal, setShowEmailModal] = useState(false);
const [showUsernameModal, setShowUsernameModal] = useState(false);
// Mock User Data
const [user] = useState({
username: 'Cyber_Producer',
email: 'alex@veza.io',
language: 'English (US)',
});
// Toggles State
const [toggles, setToggles] = useState({
emailNotif: true,
pushNotif: true,
publicProfile: true,
showActivity: true,
});
const toggle = (key: keyof typeof toggles) => {
setToggles((prev) => ({ ...prev, [key]: !prev[key] }));
addToast('Settings updated', 'info');
};
if (view === 'delete') {
return (
<DeleteAccountView
onBack={() => setView('main')}
onLogout={() => window.location.reload()}
/>
);
}
return (
<div className="space-y-8 animate-fadeIn max-w-4xl mx-auto pb-10">
{/* 1. IDENTITY SECTION */}
<Card variant="default">
<h3 className="text-lg font-bold text-white mb-6 flex items-center gap-2">
<User className="w-5 h-5 text-kodo-steel" /> Identity & Login
</h3>
<div className="space-y-6">
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 p-4 bg-kodo-ink rounded-lg border border-kodo-steel/50">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-kodo-slate rounded-full flex items-center justify-center text-kodo-content-dim">
<Mail className="w-5 h-5" />
</div>
<div>
<div className="text-sm font-bold text-white">
Email Address
</div>
<div className="text-xs text-kodo-content-dim">{user.email}</div>
</div>
</div>
<Button
variant="ghost"
size="sm"
className="border border-kodo-steel"
onClick={() => setShowEmailModal(true)}
>
Change Email
</Button>
</div>
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 p-4 bg-kodo-ink rounded-lg border border-kodo-steel/50">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-kodo-slate rounded-full flex items-center justify-center text-kodo-content-dim">
<User className="w-5 h-5" />
</div>
<div>
<div className="text-sm font-bold text-white">Username</div>
<div className="text-xs text-kodo-content-dim">@{user.username}</div>
</div>
</div>
<Button
variant="ghost"
size="sm"
className="border border-kodo-steel"
onClick={() => setShowUsernameModal(true)}
>
Change Username
</Button>
</div>
</div>
</Card>
{/* 2. PREFERENCES SECTION */}
<Card variant="default">
<h3 className="text-lg font-bold text-white mb-6 flex items-center gap-2">
<Monitor className="w-5 h-5 text-kodo-magenta" /> Preferences
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<label className="block text-sm font-bold text-kodo-content-dim mb-3">
Interface Theme
</label>
<div className="grid grid-cols-3 gap-2">
{[
{
id: ThemeVariant.NEON,
label: 'Dark',
icon: <Moon className="w-4 h-4" />,
},
{
id: ThemeVariant.LIGHT,
label: 'Light',
icon: <Sun className="w-4 h-4" />,
},
{
id: ThemeVariant.GAMING,
label: 'Game',
icon: <Laptop className="w-4 h-4" />,
},
].map((opt) => (
<button
key={opt.id}
onClick={() => setTheme(opt.id)}
className={`flex flex-col items-center justify-center gap-2 p-4 rounded-lg border transition-all ${theme === opt.id ? 'bg-kodo-cyan/10 border-kodo-cyan text-kodo-cyan' : 'bg-kodo-ink border-kodo-steel text-kodo-content-dim hover:text-white'}`}
>
{opt.icon}
<span className="text-xs font-bold">{opt.label}</span>
</button>
))}
</div>
</div>
<div>
<label className="block text-sm font-bold text-kodo-content-dim mb-3">
Language
</label>
<div className="relative">
<Globe className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-kodo-content-dim" />
<select className="w-full bg-kodo-ink border border-kodo-steel rounded-lg py-2.5 pl-10 pr-4 text-white text-sm focus:border-kodo-steel outline-none appearance-none cursor-pointer hover:border-kodo-steel transition-colors">
<option>English (US)</option>
<option>Japanese</option>
<option>French</option>
<option>Spanish</option>
<option>German</option>
</select>
</div>
</div>
</div>
</Card>
{/* 3. NOTIFICATIONS & PRIVACY */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
<Card variant="default">
<h3 className="text-lg font-bold text-white mb-6 flex items-center gap-2">
<Bell className="w-5 h-5 text-kodo-lime" /> Notifications
</h3>
<div className="space-y-4">
<div className="flex items-center justify-between">
<span className="text-sm text-kodo-text-main">Email Notifications</span>
<Switch
checked={toggles.emailNotif}
onChange={() => toggle('emailNotif')}
/>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-kodo-text-main">Push Notifications</span>
<Switch
checked={toggles.pushNotif}
onChange={() => toggle('pushNotif')}
/>
</div>
</div>
</Card>
<Card variant="default">
<h3 className="text-lg font-bold text-white mb-6 flex items-center gap-2">
<Lock className="w-5 h-5 text-kodo-gold" /> Privacy
</h3>
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<span className="text-sm text-kodo-text-main block">
Public Profile
</span>
<span className="text-[10px] text-kodo-content-dim">
Allow others to find you
</span>
</div>
<Switch
checked={toggles.publicProfile}
onChange={() => toggle('publicProfile')}
/>
</div>
<div className="flex items-center justify-between">
<div>
<span className="text-sm text-kodo-text-main block">
Activity Status
</span>
<span className="text-[10px] text-kodo-content-dim">
Show when you are online
</span>
</div>
<Switch
checked={toggles.showActivity}
onChange={() => toggle('showActivity')}
/>
</div>
</div>
</Card>
</div>
{/* 4. DANGER ZONE */}
<Card
variant="default"
className="border-kodo-red/30 relative overflow-hidden"
>
<div className="absolute top-0 left-0 w-1 h-full bg-kodo-red"></div>
<h3 className="text-lg font-bold text-white mb-2 flex items-center gap-2">
<ShieldAlert className="w-5 h-5 text-kodo-red" /> Danger Zone
</h3>
<p className="text-kodo-content-dim text-sm mb-6">
Irreversible actions. Proceed with caution.
</p>
<div className="flex flex-col md:flex-row items-center justify-between gap-4 p-4 bg-kodo-red/5 rounded border border-kodo-red/20">
<div>
<div className="font-bold text-white text-sm">Delete Account</div>
<div className="text-xs text-kodo-content-dim">
Permanently remove your account and all data.
</div>
</div>
<Button
variant="ghost"
className="text-kodo-red hover:bg-kodo-red hover:text-white border border-kodo-red/50 w-full md:w-auto"
onClick={() => setView('delete')}
>
DELETE ACCOUNT
</Button>
</div>
</Card>
{/* MODALS */}
{showEmailModal && (
<ChangeEmailModal
onClose={() => setShowEmailModal(false)}
currentEmail={user.email}
/>
)}
{showUsernameModal && (
<ChangeUsernameModal
onClose={() => setShowUsernameModal(false)}
currentUsername={user.username}
/>
)}
</div>
);
};