import { useState } from 'react'; import { useAuth } from '../contexts/AuthContext.jsx'; import { useToast } from '../contexts/ToastContext.jsx'; import { api } from '../utils/api.js'; import Avatar from './Avatar.jsx'; export default function ProfileModal({ onClose }) { const { user, updateUser } = useAuth(); const toast = useToast(); const [displayName, setDisplayName] = useState(user?.display_name || ''); const [savedDisplayName, setSavedDisplayName] = useState(user?.display_name || ''); const [displayNameWarning, setDisplayNameWarning] = useState(''); const [aboutMe, setAboutMe] = useState(user?.about_me || ''); const [currentPw, setCurrentPw] = useState(''); const [newPw, setNewPw] = useState(''); const [confirmPw, setConfirmPw] = useState(''); const [loading, setLoading] = useState(false); const [tab, setTab] = useState('profile'); // 'profile' | 'password' | 'notifications' const [pushTesting, setPushTesting] = useState(false); const [pushResult, setPushResult] = useState(null); const [hideAdminTag, setHideAdminTag] = useState(!!user?.hide_admin_tag); const [allowDm, setAllowDm] = useState(user?.allow_dm !== 0); const handleSaveProfile = async () => { if (displayNameWarning) return toast('Display name is already in use', 'error'); setLoading(true); try { const { user: updated } = await api.updateProfile({ displayName, aboutMe, hideAdminTag, allowDm }); updateUser(updated); setSavedDisplayName(displayName); toast('Profile updated', 'success'); } catch (e) { toast(e.message, 'error'); } finally { setLoading(false); } }; const handleAvatarUpload = async (e) => { const file = e.target.files?.[0]; if (!file) return; try { const { avatarUrl } = await api.uploadAvatar(file); updateUser({ avatar: avatarUrl }); toast('Avatar updated', 'success'); } catch (e) { toast(e.message, 'error'); } }; const handleChangePassword = async () => { if (newPw !== confirmPw) return toast('Passwords do not match', 'error'); if (newPw.length < 8) return toast('Password too short (min 8)', 'error'); setLoading(true); try { await api.changePassword({ currentPassword: currentPw, newPassword: newPw }); toast('Password changed', 'success'); setCurrentPw(''); setNewPw(''); setConfirmPw(''); } catch (e) { toast(e.message, 'error'); } finally { setLoading(false); } }; return (
e.target === e.currentTarget && onClose()}>

My Profile

{/* Avatar */}
{!user?.is_default_admin && ( )}
{user?.display_name || user?.name}
{user?.email}
{user?.role}
{/* Tabs */}
{tab === 'profile' && (
{ const val = e.target.value; setDisplayName(val); setDisplayNameWarning(''); if (val && val !== user?.display_name) { try { const { taken } = await api.checkDisplayName(val); if (taken) setDisplayNameWarning('Display name is already in use'); } catch {} } }} placeholder={user?.name} autoComplete="new-password" autoCorrect="off" autoCapitalize="words" spellCheck={false} style={{ borderColor: displayNameWarning ? '#e53935' : undefined }} /> {displayName !== savedDisplayName ? null : savedDisplayName ? ( ) : null}
{displayNameWarning && {displayNameWarning}} {savedDisplayName && Username: {user?.name}}