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; twoFactor: { enabled: boolean; qr_code: string | null; secret: string | null; 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 (

{title}

{description}

{children}
); } function InputField({ label, id, type = 'text', value, onChange, error, placeholder, required = false }: any) { return (
{error &&

{error}

}
); } 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 }: SettingsProps) { const { user } = usePage().props.auth; const [activeTab, setActiveTab] = useState(getSettingsTabFromHash); useEffect(() => { const onHashChange = () => setActiveTab(getSettingsTabFromHash()); window.addEventListener('hashchange', onHashChange); return () => window.removeEventListener('hashchange', onHashChange); }, []); 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([]); 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 = (e: React.SyntheticEvent) => { e.preventDefault(); 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.'); }, }); } }; return ( {/* Header Section */}

Account Settings

Manage your personal credentials and security preferences

{/* Tabs Row */}
{/* Content Area */}
{activeTab === 'profile' && (
setProfileData('first_name', e.target.value)} error={profileErrors.first_name} required placeholder="e.g. John" /> setProfileData('last_name', e.target.value)} error={profileErrors.last_name} required placeholder="e.g. Doe" />
setProfileData('email', e.target.value)} error={profileErrors.email} required placeholder="e.g. john.doe@example.com" /> setProfileData('phone', e.target.value)} error={(profileErrors as any).phone} placeholder="e.g. +62 812 3456 7890" />