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

168 lines
6 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';
2026-01-07 18:39:21 +00:00
import { Lock, Key, Plus, AlertCircle, CheckCircle } from 'lucide-react';
import { useToast } from '../../../components/feedback/ToastProvider';
2026-01-07 18:39:21 +00:00
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',
);
2026-01-07 18:39:21 +00:00
// 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">
aesthetic-improvements: reduce decorative cyan across multiple component categories (80/20 rule, batch 11) - Social: FeedView, ConnectionsView, GroupsView, ExploreView, GroupDetailView loading spinners and decorative text, CreatePostModal decorative select text and hashtag links, PostCard decorative tag links and waveform bars and view comments link, CreateGroupModal decorative icon (9 instances) - Settings: DataExportModal decorative icon, LoginHistory decorative IP text, AppearanceSettingsView decorative icon and selected theme checkmark, BackupsView decorative icon, CloudIntegrationView decorative icon, AccessibilitySettingsView decorative icon, SecuritySettings decorative icon, PasskeyModal decorative icon and loading spinner (8 instances) - Studio: ProjectsManager loading spinner and progress percentage text, CloudFileBrowser decorative music icons, AIToolsView decorative music icon, ConnectivityView decorative icon, CreateProjectModal decorative icon, CloudSettingsView decorative icon (6 instances) - Admin: AdminDashboardView loading spinner and decorative chart bars and icon, AdminSettingsView decorative icon, AdminModerationView loading spinner, AdminUsersView loading spinner (5 instances) - Inventory: InventoryView loading spinner, EquipmentCard decorative price icon, EquipmentDetailView loading spinner and decorative icons and price text, AddEquipmentView decorative icon (5 instances) - Seller: CreateProductView decorative icon, SellerDashboardView loading spinner and decorative icon and sales text (3 instances) - Live: LiveStreamDetailView decorative streamer name text (1 instance) - Developer: DeveloperDashboardView loading spinner, WebhooksView decorative icon (2 instances) - Upload: BulkUploadModal decorative icon, FilePreviewCard decorative audio file icon, MetadataForm decorative button text, CoverArtUploadModal decorative icon, LyricsEditorModal decorative icon (5 instances) - Notifications: NotificationItem decorative follow icon and mark as read button, NotificationBell decorative mark all read link (3 instances) - Total: ~46 files, ~46 instances replaced - Preserved: Active/selected states (CloudFileBrowser selected files checkmarks, CreatePostModal post type active state, GroupCard/GroupDetailView public/private badges - semantic indicators, DataExportModal checkbox accents - focus/interaction, AppearanceSettingsView selected theme - active state, PasskeyModal checkbox accent - focus/interaction, LyricsEditorModal checkbox accent - focus/interaction, FileUploadZone drag active state - active state, EquipmentDetailView support link - functional link, FlashSaleModal link - functional link, EquipmentDetailView image indicator dots - active state), primary actions, design system variants - Action 11.3.1.3 in progress (eleventh batch: social, settings, studio, admin, inventory, seller, live, developer, upload, notifications components)
2026-01-16 10:26:33 +00:00
<Lock className="w-5 h-5 text-kodo-steel" /> Password & Authentication
</h3>
2026-01-07 18:39:21 +00:00
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
<div className="space-y-4">
2026-01-07 18:39:21 +00:00
<Input
type="password"
label="Current Password"
value={currentPassword}
onChange={(e) => setCurrentPassword(e.target.value)}
/>
<div className="relative">
2026-01-07 18:39:21 +00:00
<Input
type="password"
label="New Password"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
/>
{newPassword && (
<PasswordStrengthIndicator password={newPassword} />
)}
</div>
2026-01-07 18:39:21 +00:00
<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-kodo-content-dim 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>
2026-01-07 18:39:21 +00:00
<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-kodo-content-dim 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-kodo-text-main">MacBook Pro (Chrome)</span>
<span className="text-xs text-kodo-content-dim">Added 2d ago</span>
</div>
</div>
</div>
</div>
</div>
</Card>
{/* 2. SESSIONS & HISTORY */}
<SessionManagement />
<LoginHistory />
{/* MODALS */}
{showPasskeyModal && (
2026-01-07 18:39:21 +00:00
<PasskeyModal
onClose={() => setShowPasskeyModal(false)}
onSuccess={() => addToast('Passkey registered', 'success')}
/>
)}
</div>
);
};