Files

566 lines
35 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
import { Head, usePage, useForm, router } from '@inertiajs/react';
import { PageProps } from '@/types';
import Swal from 'sweetalert2';
import { swal } from '@/lib/swal';
// FilePond
import { FilePond, registerPlugin } from 'react-filepond';
import 'filepond/dist/filepond.min.css';
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type';
registerPlugin(FilePondPluginImagePreview, FilePondPluginFileValidateType);
interface SettingsProps extends PageProps {
mustVerifyEmail: boolean;
status?: string;
twoFactorSettings: {
totp_allowed: boolean;
email_allowed: boolean;
};
twoFactor: {
enabled: boolean;
qr_code: string | null;
secret: string | null;
email_enabled: boolean;
smtp_configured: boolean;
recovery_codes: string[];
};
}
/* ─── Reusable Components from System Settings ─────────────────── */
function SectionCard({ title, description, children, delay = '0s', variant = 'default' }: { title: string; description: string; children: React.ReactNode; delay?: string; variant?: 'default' | 'danger' }) {
const isDanger = variant === 'danger';
return (
<div className={`bg-white rounded-2xl border ${isDanger ? 'border-red-200 shadow-none' : 'border-gray-100 shadow-sm'} overflow-hidden h-full flex flex-col anim-up`} style={{ animationDelay: delay }}>
<div className={`px-6 py-4 border-b ${isDanger ? 'border-red-100 bg-red-50' : 'border-gray-50 bg-gray-50/30'}`}>
<h2 className={`text-sm font-bold tracking-tight ${isDanger ? 'text-red-600' : 'text-[#3D4E4B]'}`}>{title}</h2>
<p className={`text-xs font-semibold tracking-tight mt-1 ${isDanger ? 'text-red-400' : 'text-gray-400'}`}>{description}</p>
</div>
<div className="p-8 flex-1">{children}</div>
</div>
);
}
function InputField({ label, id, type = 'text', value, onChange, error, placeholder, required = false }: any) {
return (
<div className="space-y-1.5">
<label htmlFor={id} className="block text-xs font-semibold text-gray-500 tracking-tight ml-1">
{label} {required && <span className="text-red-500">*</span>}
</label>
<input
id={id} type={type} value={value} onChange={onChange} placeholder={placeholder}
className={`input-field${error ? ' is-error' : ''}`}
/>
{error && <p className="text-xs text-red-500 font-semibold ml-1 mt-1">{error}</p>}
</div>
);
}
const SETTINGS_TABS = ['profile', 'security', '2fa', 'danger'] as const;
type SettingsTab = typeof SETTINGS_TABS[number];
function getSettingsTabFromHash(): SettingsTab {
const hash = window.location.hash.replace('#', '') as SettingsTab;
return SETTINGS_TABS.includes(hash) ? hash : 'profile';
}
export default function SettingsIndex({ twoFactor, twoFactorSettings }: SettingsProps) {
const { user } = usePage<PageProps>().props.auth;
const [activeTab, setActiveTab] = useState<SettingsTab>(() => {
const hash = getSettingsTabFromHash();
if (hash === '2fa' && !(twoFactorSettings.totp_allowed || twoFactorSettings.email_allowed)) {
return 'profile';
}
return hash;
});
useEffect(() => {
const onHashChange = () => {
const hash = getSettingsTabFromHash();
if (hash === '2fa' && !(twoFactorSettings.totp_allowed || twoFactorSettings.email_allowed)) {
setActiveTab('profile');
} else {
setActiveTab(hash);
}
};
window.addEventListener('hashchange', onHashChange);
return () => window.removeEventListener('hashchange', onHashChange);
}, [twoFactorSettings]);
const switchTab = (tab: SettingsTab) => {
window.location.hash = tab;
setActiveTab(tab);
};
const { data: profileData, setData: setProfileData, post: postProfile, processing: profileProcessing, errors: profileErrors } = useForm({
first_name: user.first_name || '',
last_name: user.last_name || '',
email: user.email || '',
phone: (user as any).phone || '',
bio: (user as any).bio || '',
avatar_file: null as File | null,
_method: 'PATCH',
});
const [avatarFiles, setAvatarFiles] = useState<any[]>([]);
const handleProfileSubmit = (e: React.SyntheticEvent) => {
e.preventDefault();
postProfile(route('profile.update'), {
preserveScroll: true,
onSuccess: () => swal.success('Saved', 'Profile updated successfully.'),
});
};
const { data: passwordData, setData: setPasswordData, put: putPassword, processing: passwordProcessing, errors: passwordErrors, reset: resetPassword } = useForm({
current_password: '',
password: '',
password_confirmation: '',
});
const handlePasswordSubmit = (e: React.SyntheticEvent) => {
e.preventDefault();
putPassword(route('password.update'), {
preserveScroll: true,
onSuccess: () => {
resetPassword();
swal.success('Saved', 'Password updated successfully.');
},
});
};
const handleDeleteAccount = async () => {
const result = await swal.confirm('Delete account?', 'This action is irreversible.', 'Delete Permanently');
if (result.isConfirmed) {
const { value: password } = await Swal.fire({
title: 'Confirm Password',
input: 'password',
inputPlaceholder: 'Enter your current password',
showCancelButton: true,
confirmButtonText: 'Delete',
confirmButtonColor: '#dc2626',
});
if (password) {
router.delete(route('profile.destroy'), {
data: { password }, preserveScroll: true,
onSuccess: () => swal.success('Deleted', 'Account removed.'),
onError: (errs) => swal.error('Error', errs.password || 'Incorrect password.'),
});
}
}
};
const initials = `${user.first_name?.charAt(0) || ''}${user.last_name?.charAt(0) || ''}`.toUpperCase();
// 2FA
const [copiedSecret, setCopiedSecret] = useState(false);
const [showCodes, setShowCodes] = useState(false);
const twoFactorForm = useForm({ code: '' });
const copySecret = () => {
navigator.clipboard.writeText(twoFactor.secret || '');
setCopiedSecret(true);
setTimeout(() => setCopiedSecret(false), 2000);
};
const handleEnable2FA = async (e: React.SyntheticEvent) => {
e.preventDefault();
if (twoFactor.email_enabled) {
const warning = await swal.confirm(
'Deactivate Email 2FA?',
'Enabling Google Authenticator will automatically deactivate Email Two-Factor Authentication. Do you want to proceed?',
'Proceed'
);
if (!warning.isConfirmed) return;
}
twoFactorForm.post(route('two-factor.enable'), {
preserveScroll: true,
onSuccess: () => { twoFactorForm.reset(); swal.success('Enabled', '2FA is now active on your account.'); },
});
};
const handleDisable2FA = async () => {
const { value: password } = await Swal.fire({
title: 'Disable 2FA',
text: 'Enter your password to confirm.',
input: 'password',
inputPlaceholder: 'Your current password',
showCancelButton: true,
confirmButtonText: 'Disable',
confirmButtonColor: '#dc2626',
});
if (password) {
router.post(route('two-factor.disable'), { password }, {
preserveScroll: true,
onSuccess: () => swal.success('Disabled', '2FA has been disabled.'),
});
}
};
const handleRegenerate = async () => {
const result = await swal.confirm('Regenerate Codes?', 'Old recovery codes will be invalidated.', 'Regenerate');
if (result.isConfirmed) {
router.post(route('two-factor.recovery-codes'), {}, {
preserveScroll: true,
onSuccess: () => { setShowCodes(true); swal.success('Regenerated', 'New recovery codes generated.'); },
});
}
};
const handleToggleEmail2FA = async (enable: boolean) => {
if (enable && !twoFactor.smtp_configured) {
Swal.fire({
icon: 'warning',
title: 'SMTP Mail Server Not Set Up',
text: 'Two-Factor Authentication via Email cannot be enabled because the system SMTP configurations are not set up yet. Please configure the SMTP settings under System Settings (or contact your Administrator) first.',
confirmButtonColor: '#3D4E4B',
});
return;
}
if (enable && twoFactor.enabled) {
const warning = await swal.confirm(
'Switch to Email 2FA?',
'Enabling Email 2FA will automatically deactivate your Google Authenticator setup. Do you want to proceed?',
'Proceed'
);
if (!warning.isConfirmed) return;
}
const { value: password } = await Swal.fire({
title: enable ? 'Enable Email 2FA' : 'Disable Email 2FA',
text: 'Enter your password to confirm.',
input: 'password',
inputPlaceholder: 'Your current password',
showCancelButton: true,
confirmButtonText: 'Confirm',
confirmButtonColor: '#3D4E4B',
});
if (password) {
router.post(route('two-factor.email.toggle'), { password, enabled: enable }, {
preserveScroll: true,
onSuccess: () => swal.success('Success', `Email Two-Factor Authentication has been ${enable ? 'enabled' : 'disabled'} successfully.`),
onError: (errs) => swal.error('Error', errs.password || 'Incorrect password.'),
});
}
};
return (
<AuthenticatedLayout>
<Head title="Account Settings" />
{/* Header Section */}
<div className="flex items-center justify-between mb-8 anim-down">
<div>
<h1 className="text-xl font-bold text-[#3D4E4B] tracking-tight leading-none">Account Settings</h1>
<p className="text-sm font-semibold text-gray-400 tracking-tight mt-2">Manage your personal credentials and security preferences</p>
</div>
</div>
{/* Tabs Row */}
<div className="flex items-center gap-1 border-b border-gray-100 w-full mb-8 anim-down" style={{ animationDelay: '0.05s' }}>
<button type="button" onClick={() => switchTab('profile')}
className={`relative pb-3 px-1 mr-8 text-sm font-bold tracking-tight transition-colors ${activeTab === 'profile' ? 'text-[#3D4E4B]' : 'text-gray-400 hover:text-[#3D4E4B]'}`}>
Profile Information
{activeTab === 'profile' && <span className="absolute bottom-0 left-0 w-full h-0.5 bg-[#D4A017] rounded-t-full" />}
</button>
<button type="button" onClick={() => switchTab('security')}
className={`relative pb-3 px-1 mr-8 text-sm font-bold tracking-tight transition-colors ${activeTab === 'security' ? 'text-[#3D4E4B]' : 'text-gray-400 hover:text-[#3D4E4B]'}`}>
Security & Password
{activeTab === 'security' && <span className="absolute bottom-0 left-0 w-full h-0.5 bg-[#D4A017] rounded-t-full" />}
</button>
{(twoFactorSettings.totp_allowed || twoFactorSettings.email_allowed) && (
<button type="button" onClick={() => switchTab('2fa')}
className={`relative pb-3 px-1 mr-8 text-sm font-bold tracking-tight transition-colors ${activeTab === '2fa' ? 'text-[#3D4E4B]' : 'text-gray-400 hover:text-[#3D4E4B]'}`}>
Two-Factor Auth
{activeTab === '2fa' && <span className="absolute bottom-0 left-0 w-full h-0.5 bg-[#D4A017] rounded-t-full" />}
</button>
)}
<button type="button" onClick={() => switchTab('danger')}
className={`relative pb-3 px-1 text-sm font-bold tracking-tight transition-colors ${activeTab === 'danger' ? 'text-red-600' : 'text-gray-400 hover:text-red-600'}`}>
Danger Zone
{activeTab === 'danger' && <span className="absolute bottom-0 left-0 w-full h-0.5 bg-red-500 rounded-t-full" />}
</button>
</div>
{/* Content Area */}
<div className="space-y-8 pb-20">
{activeTab === 'profile' && (
<div className="space-y-8 anim-fade">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
<div className="lg:col-span-2">
<SectionCard title="Identity" description="Manage your public name and contact email" delay="0.1s">
<form onSubmit={handleProfileSubmit} className="space-y-8">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
<InputField label="First Name" id="first_name" value={profileData.first_name}
onChange={(e: any) => setProfileData('first_name', e.target.value)}
error={profileErrors.first_name} required placeholder="e.g. John" />
<InputField label="Last Name" id="last_name" value={profileData.last_name}
onChange={(e: any) => setProfileData('last_name', e.target.value)}
error={profileErrors.last_name} required placeholder="e.g. Doe" />
</div>
<InputField label="Email Address" id="email" type="email" value={profileData.email}
onChange={(e: any) => setProfileData('email', e.target.value)}
error={profileErrors.email} required placeholder="e.g. john.doe@example.com" />
<InputField label="Phone Number" id="phone" value={profileData.phone}
onChange={(e: any) => setProfileData('phone', e.target.value)}
error={(profileErrors as any).phone} placeholder="e.g. +62 812 3456 7890" />
<div className="space-y-1.5">
<label htmlFor="bio" className="block text-xs font-semibold text-gray-500 tracking-tight ml-1">Bio</label>
<textarea
id="bio"
value={profileData.bio}
onChange={(e: any) => setProfileData('bio', e.target.value)}
rows={3}
placeholder="A short description about yourself..."
className={`input-field py-3 resize-none${(profileErrors as any).bio ? ' is-error' : ''}`}
/>
{(profileErrors as any).bio && <p className="text-xs text-red-500 font-semibold ml-1 mt-1">{(profileErrors as any).bio}</p>}
</div>
<div className="flex justify-end pt-4 border-t border-gray-50">
<button type="submit" disabled={profileProcessing}
className="h-10 px-8 bg-[#3D4E4B] text-white text-sm font-bold tracking-tight rounded-xl hover:bg-[#2D3A38] transition-all shadow-lg shadow-[#3D4E4B]/20 disabled:opacity-60">
{profileProcessing ? 'Saving...' : 'Save Profile'}
</button>
</div>
</form>
</SectionCard>
</div>
<div className="lg:col-span-1">
<SectionCard title="Profile Photo" description="Update your avatar" delay="0.15s">
<div className="flex flex-col items-center gap-6">
<div className="w-24 h-24 rounded-2xl bg-[#3D4E4B] flex items-center justify-center text-white text-2xl font-bold shadow-lg shadow-[#3D4E4B]/10 overflow-hidden border-2 border-white">
{user.avatar_url ? <img src={user.avatar_url} className="w-full h-full object-cover" /> : initials}
</div>
<div className="w-full">
<FilePond files={avatarFiles} onupdatefiles={items => { setAvatarFiles(items); setProfileData('avatar_file', items[0]?.file as File || null); }}
allowMultiple={false} maxFiles={1} labelIdle='Drop Photo here' />
</div>
</div>
</SectionCard>
</div>
</div>
</div>
)}
{activeTab === 'security' && (
<div className="max-w-4xl anim-fade">
<SectionCard title="Password" description="Update your secure access key" delay="0.1s">
<form onSubmit={handlePasswordSubmit} className="space-y-8">
<div className="max-w-md">
<InputField label="Current Password" id="current_password" type="password"
value={passwordData.current_password}
onChange={(e: any) => setPasswordData('current_password', e.target.value)}
error={passwordErrors.current_password} required placeholder="••••••••" />
</div>
<div className="h-px bg-gray-50 -mx-8" />
<div className="grid grid-cols-1 sm:grid-cols-2 gap-8">
<InputField label="New Password" id="password" type="password"
value={passwordData.password}
onChange={(e: any) => setPasswordData('password', e.target.value)}
error={passwordErrors.password} required placeholder="Enter new password" />
<InputField label="Confirm New Password" id="password_confirmation" type="password"
value={passwordData.password_confirmation}
onChange={(e: any) => setPasswordData('password_confirmation', e.target.value)}
error={(passwordErrors as any).password_confirmation} required placeholder="Repeat new password" />
</div>
<div className="flex justify-end pt-4 border-t border-gray-50">
<button type="submit" disabled={passwordProcessing}
className="h-10 px-8 bg-[#3D4E4B] text-white text-sm font-bold tracking-tight rounded-xl hover:bg-[#2D3A38] transition-all shadow-lg shadow-[#3D4E4B]/20 disabled:opacity-60">
{passwordProcessing ? 'Updating...' : 'Update Password'}
</button>
</div>
</form>
</SectionCard>
</div>
)}
{activeTab === '2fa' && (
<div className="max-w-4xl space-y-8 anim-fade">
<div className="p-5 bg-amber-50 border border-amber-200 rounded-2xl flex items-start gap-3">
<svg className="w-5 h-5 text-amber-500 mt-0.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" />
</svg>
<div>
<p className="text-xs font-bold text-amber-800 mb-1">Two-Factor Authentication (2FA)</p>
<p className="text-[11px] text-amber-700 font-medium leading-relaxed">
2FA menambah lapisan keamanan ekstra dengan meminta kode OTP dari aplikasi authenticator setiap kali login.
</p>
</div>
</div>
{twoFactorSettings.totp_allowed && (
!twoFactor.enabled ? (
<SectionCard title="Setup Authenticator App" description="Scan QR code dengan Google Authenticator, Authy, atau TOTP app lainnya">
<div className="flex flex-col md:flex-row gap-10 items-center md:items-start">
<div className="shrink-0">
<div className="p-4 bg-white border-2 border-gray-100 rounded-2xl inline-block shadow-sm">
{twoFactor.qr_code && <img src={twoFactor.qr_code} alt="2FA QR Code" className="w-44 h-44" />}
</div>
</div>
<div className="flex-1 space-y-6">
<div className="space-y-3">
{[
'Install aplikasi authenticator (Google Authenticator, Authy, 1Password)',
'Scan QR code atau masukkan manual key di bawah',
'Masukkan kode 6 digit dari aplikasi untuk mengaktifkan',
].map((step, i) => (
<div key={i} className="flex items-start gap-3">
<div className="w-6 h-6 rounded-full bg-[#3D4E4B] text-white text-[10px] font-black flex items-center justify-center shrink-0 mt-0.5">{i + 1}</div>
<p className="text-xs font-medium text-gray-500 leading-relaxed pt-0.5">{step}</p>
</div>
))}
</div>
<div>
<label className="block text-xs font-semibold text-gray-400 mb-1.5">Manual Key</label>
<div className="flex items-center gap-2">
<code className="flex-1 text-xs font-mono bg-gray-50 border border-gray-100 rounded-xl px-4 py-3 text-[#3D4E4B] tracking-wider">
{twoFactor.secret}
</code>
<button onClick={copySecret} type="button"
className="shrink-0 h-11 px-4 border border-gray-200 rounded-xl text-xs font-bold text-gray-500 hover:bg-gray-50 transition-all">
{copiedSecret ? '✓ Copied' : 'Copy'}
</button>
</div>
</div>
<form onSubmit={handleEnable2FA} className="space-y-3">
<div>
<label className="block text-xs font-semibold text-gray-400 mb-1.5">Verification Code *</label>
<input type="text" inputMode="numeric" maxLength={6}
value={twoFactorForm.data.code}
onChange={e => twoFactorForm.setData('code', e.target.value)}
className="input-field w-full text-center tracking-[0.5em] font-bold text-lg"
placeholder="000000" />
{twoFactorForm.errors.code && <p className="text-xs text-red-500 font-semibold mt-1">{twoFactorForm.errors.code}</p>}
</div>
<button type="submit" disabled={twoFactorForm.processing || twoFactorForm.data.code.length < 6}
className="w-full h-11 bg-[#3D4E4B] text-white text-xs font-bold rounded-xl hover:bg-[#2D3A38] transition-all disabled:opacity-60">
{twoFactorForm.processing ? 'Verifying...' : 'Enable Two-Factor Authentication'}
</button>
</form>
</div>
</div>
</SectionCard>
) : (
<div className="space-y-4">
<div className="bg-white rounded-2xl border border-emerald-100 shadow-sm p-6 flex items-center gap-4">
<div className="w-12 h-12 rounded-xl bg-emerald-50 flex items-center justify-center shrink-0">
<svg className="w-6 h-6 text-emerald-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
</div>
<div className="flex-1">
<div className="text-sm font-bold text-[#3D4E4B]">Two-Factor Authentication Aktif</div>
<div className="text-xs text-gray-400 font-medium mt-0.5">Akun Anda dilindungi dengan TOTP authentication.</div>
</div>
<button onClick={handleDisable2FA} type="button"
className="h-9 px-5 text-xs font-bold text-red-500 border border-red-200 rounded-xl hover:bg-red-50 transition-all">
Disable 2FA
</button>
</div>
<SectionCard title="Recovery Codes" description="Simpan kode ini dengan aman — gunakan jika kehilangan akses ke authenticator">
<div className="space-y-4">
<div className="flex items-center gap-2">
<button onClick={() => setShowCodes(!showCodes)} type="button"
className="h-8 px-4 text-xs font-bold text-[#3D4E4B] border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
{showCodes ? 'Hide' : 'Show Codes'}
</button>
<button onClick={handleRegenerate} type="button"
className="h-8 px-4 text-xs font-bold text-[#D4A017] border border-amber-200 rounded-lg hover:bg-amber-50 transition-all">
Regenerate
</button>
</div>
{showCodes && twoFactor.recovery_codes.length > 0 && (
<div>
<div className="grid grid-cols-2 gap-2">
{twoFactor.recovery_codes.map((code, i) => (
<code key={i} className="px-4 py-2.5 bg-gray-50 border border-gray-100 rounded-xl text-xs font-mono text-[#3D4E4B] tracking-wider text-center">
{code}
</code>
))}
</div>
<p className="text-[11px] text-amber-600 font-semibold mt-3"> Setiap kode hanya bisa digunakan sekali.</p>
</div>
)}
</div>
</SectionCard>
</div>
)
)}
{/* Email 2FA Setup */}
{twoFactorSettings.email_allowed && (
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm p-6 flex items-center gap-4">
<div className="w-12 h-12 rounded-xl bg-blue-50 flex items-center justify-center shrink-0">
<svg className="w-6 h-6 text-[#D4A017]" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
<div className="flex-1">
<div className="text-sm font-bold text-[#3D4E4B]">Two-Factor Authentication via Email</div>
<div className="text-xs text-gray-400 font-medium mt-0.5">
{twoFactor.email_enabled
? 'Email 2FA is active. Every login attempt will require an OTP code sent to your email.'
: 'Receive a 6-digit OTP code in your email to secure your login sessions.'}
</div>
{!twoFactor.smtp_configured && (
<div className="flex items-center gap-1.5 mt-2 text-[11px] font-bold text-amber-600 bg-amber-50 px-2.5 py-1 rounded-lg w-fit border border-amber-200">
<span className="text-sm"></span>
<span>SMTP Mail Server is not configured. Setup required.</span>
</div>
)}
</div>
{twoFactor.email_enabled ? (
<button onClick={() => handleToggleEmail2FA(false)} type="button"
className="h-9 px-5 text-xs font-bold text-red-500 border border-red-200 rounded-xl hover:bg-red-50 transition-all">
Disable Email 2FA
</button>
) : (
<button onClick={() => handleToggleEmail2FA(true)} type="button"
className="h-9 px-5 text-xs font-bold text-[#3D4E4B] border border-gray-200 rounded-xl hover:bg-gray-50 transition-all">
Enable Email 2FA
</button>
)}
</div>
)}
</div>
)}
{activeTab === 'danger' && (
<div className="max-w-4xl anim-fade">
<SectionCard title="Account Lifecycle" description="Critical and irreversible account actions" delay="0.1s">
<div className="flex items-center justify-between gap-10 p-6 rounded-2xl bg-red-50 border border-red-100">
<div className="flex items-center gap-6">
<div className="w-14 h-14 rounded-2xl bg-white border border-red-100 flex items-center justify-center text-red-600 shrink-0">
<svg className="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}><path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
</div>
<div>
<p className="text-base font-bold text-red-900 leading-none">Delete Account Permanently</p>
<p className="text-xs text-red-700/60 font-semibold mt-2 leading-relaxed">
Proceeding will scrub your identity, logs, and settings from our database. This action is irreversible.
</p>
</div>
</div>
<button onClick={handleDeleteAccount}
className="h-11 px-8 bg-red-600 text-white text-xs font-bold uppercase tracking-widest rounded-xl hover:bg-red-700 transition-all shrink-0">
Delete Account
</button>
</div>
</SectionCard>
</div>
)}
</div>
</AuthenticatedLayout>
);
}