veza/apps/web/src/components/settings/security/SecuritySettings.tsx
senke 69577e9980 feat(ui): semantic tokens in RolesPage, SettingsPage, Toast, QueueView
- SecuritySettings: row bg-white/5 → bg-muted/30
- Toast: close button hover:bg-black/10 → hover:bg-muted/50
- QueueView: autoplay toggle thumb bg-white → bg-background
- RolesPage: cards/headers border-white/5, bg-black/40 → border-border, bg-card/80; headings text-white → text-foreground; row hover, inputs, badge → semantic
- SettingsPage: wrapper and tabs border/bg → border-border, bg-card/80, bg-muted/20; section cards; System Config title text-foreground

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-10 09:45:30 +01:00

167 lines
6 KiB
TypeScript

import React, { useState } from 'react';
import { Card } from '../../ui/card';
import { Button } from '../../ui/button';
import { Input } from '../../ui/input';
import { Lock, Key, Plus, AlertCircle, CheckCircle } from 'lucide-react';
import { useToast } from '../../../components/feedback/ToastProvider';
import { PasswordStrengthIndicator } from '@/features/auth/components/PasswordStrengthIndicator';
import { TwoFactorSetup } from './TwoFactorSetup';
import { PasskeyModal } from './PasskeyModal';
import { SessionManagement } from './SessionManagement';
import { LoginHistory } from './LoginHistory';
export const SecuritySettings: React.FC = () => {
const { addToast } = useToast();
const [view, setView] = useState<'main' | '2fa' | 'sessions' | 'history'>(
'main',
);
// Forms & Modals
const [currentPassword, setCurrentPassword] = useState('');
const [newPassword, setNewPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [showPasskeyModal, setShowPasskeyModal] = useState(false);
const [is2FAEnabled, setIs2FAEnabled] = useState(false);
const handlePasswordUpdate = () => {
if (newPassword !== confirmPassword) {
addToast('Passwords do not match', 'error');
return;
}
addToast('Password successfully updated', 'success');
setCurrentPassword('');
setNewPassword('');
setConfirmPassword('');
};
if (view === '2fa') {
return (
<TwoFactorSetup
onBack={() => setView('main')}
onComplete={() => {
setIs2FAEnabled(true);
setView('main');
}}
/>
);
}
return (
<div className="space-y-8 animate-fadeIn pb-10">
{/* 1. PASSWORD CHANGE */}
<Card variant="default">
<h3 className="text-xl font-bold text-foreground mb-6 flex items-center gap-2">
<Lock className="w-5 h-5 text-muted-foreground" /> Password & Authentication
</h3>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
<div className="space-y-4">
<Input
type="password"
label="Current Password"
value={currentPassword}
onChange={(e) => setCurrentPassword(e.target.value)}
/>
<div className="relative">
<Input
type="password"
label="New Password"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
/>
{newPassword && (
<PasswordStrengthIndicator password={newPassword} />
)}
</div>
<Input
type="password"
label="Confirm New Password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
<div className="pt-2 flex justify-end">
<Button
variant="primary"
onClick={handlePasswordUpdate}
disabled={!currentPassword || !newPassword}
>
Update Password
</Button>
</div>
</div>
<div className="space-y-6">
{/* 2FA Summary */}
<div className="bg-card p-6 rounded-xl border border-border">
<div className="flex justify-between items-start mb-4">
<div>
<h4 className="font-bold text-foreground text-sm">
Two-Factor Authentication
</h4>
<p className="text-xs text-muted-foreground mt-1">
Add an extra layer of security to your account.
</p>
</div>
{is2FAEnabled ? (
<span className="text-success flex items-center gap-1 text-xs font-bold border border-success/30 px-2 py-1 rounded bg-success/5">
<CheckCircle className="w-3 h-3" /> ENABLED
</span>
) : (
<span className="text-destructive flex items-center gap-1 text-xs font-bold border border-destructive/30 px-2 py-1 rounded bg-destructive/5">
<AlertCircle className="w-3 h-3" /> DISABLED
</span>
)}
</div>
<Button
variant="secondary"
className="w-full"
onClick={() => setView('2fa')}
>
{is2FAEnabled ? 'Manage 2FA Settings' : 'Enable 2FA'}
</Button>
</div>
{/* Passkeys */}
<div className="bg-card p-6 rounded-xl border border-border">
<div className="flex justify-between items-start mb-4">
<div>
<h4 className="font-bold text-foreground text-sm flex items-center gap-2">
<Key className="w-4 h-4 text-warning" /> Passkeys
</h4>
<p className="text-xs text-muted-foreground mt-1">
Sign in with FaceID, TouchID, or device PIN.
</p>
</div>
<Button
variant="ghost"
size="icon"
onClick={() => setShowPasskeyModal(true)}
>
<Plus className="w-4 h-4" />
</Button>
</div>
<div className="space-y-2">
<div className="flex justify-between items-center text-sm p-2 rounded bg-muted/30">
<span className="text-foreground">MacBook Pro (Chrome)</span>
<span className="text-xs text-muted-foreground">Added 2d ago</span>
</div>
</div>
</div>
</div>
</div>
</Card>
{/* 2. SESSIONS & HISTORY */}
<SessionManagement />
<LoginHistory />
{/* MODALS */}
{showPasskeyModal && (
<PasskeyModal
onClose={() => setShowPasskeyModal(false)}
onSuccess={() => addToast('Passkey registered', 'success')}
/>
)}
</div>
);
};