veza/apps/web/src/components/settings/security/SecuritySettings.tsx

136 lines
5.5 KiB
TypeScript
Raw Normal View History

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 } from 'lucide-react';
import { useToast } from '../../../context/ToastContext';
import { PasswordStrengthIndicator } from '../../auth/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-white mb-6 flex items-center gap-2">
<Lock className="w-5 h-5 text-kodo-cyan" /> 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-kodo-ink p-6 rounded-xl border border-kodo-steel">
<div className="flex justify-between items-start mb-4">
<div>
<h4 className="font-bold text-white text-sm">Two-Factor Authentication</h4>
<p className="text-xs text-gray-400 mt-1">Add an extra layer of security to your account.</p>
</div>
{is2FAEnabled ? (
<span className="text-kodo-lime flex items-center gap-1 text-xs font-bold border border-kodo-lime/30 px-2 py-1 rounded bg-kodo-lime/5"><CheckCircle className="w-3 h-3" /> ENABLED</span>
) : (
<span className="text-kodo-red flex items-center gap-1 text-xs font-bold border border-kodo-red/30 px-2 py-1 rounded bg-kodo-red/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-kodo-ink p-6 rounded-xl border border-kodo-steel">
<div className="flex justify-between items-start mb-4">
<div>
<h4 className="font-bold text-white text-sm flex items-center gap-2">
<Key className="w-4 h-4 text-kodo-gold" /> Passkeys
</h4>
<p className="text-xs text-gray-400 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-white/5">
<span className="text-gray-300">MacBook Pro (Chrome)</span>
<span className="text-xs text-gray-500">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>
);
};