import { useState, useCallback, useEffect } from 'react'; import { useAuth } from '../../contexts/AuthContext'; import { bugsApi, forumApi, usersApi } from '../../utils/api'; import { formatDate } from '../../utils/format'; import { Link } from 'react-router-dom'; import type { BugReport, ForumThread } from '../../types'; type Tab = 'profile' | 'threads' | 'bugs' | 'password'; export default function AccountPage() { const { user, updateUsername } = useAuth(); const [activeTab, setActiveTab] = useState('profile'); const [userThreads, setUserThreads] = useState([]); const [userBugs, setUserBugs] = useState([]); useEffect(() => { if (!user) return; forumApi.getThreads({ limit: 200 }) .then((res) => setUserThreads(res.data.filter((t) => t.authorId === user.id))) .catch(() => setUserThreads([])); bugsApi.getBugs({ limit: 200 }) .then((res) => setUserBugs(res.data.filter((b) => b.submittedById === user.id))) .catch(() => setUserBugs([])); }, [user]); const tabs: { id: Tab; label: string }[] = [ { id: 'profile', label: 'Profile' }, { id: 'threads', label: `Threads (${userThreads.length})` }, { id: 'bugs', label: `Bug Reports (${userBugs.length})` }, { id: 'password', label: 'Change Password' }, ]; if (!user) return null; return (
My Account

{user.username}

{/* Tabs */}
{tabs.map(({ id, label }) => ( ))}
{/* Profile Tab */} {activeTab === 'profile' && ( )} {/* Threads Tab */} {activeTab === 'threads' && (
{userThreads.length === 0 ? (
You haven't posted any threads yet.{' '} Go to Forum
) : ( userThreads.map((t) => (
{t.title} {formatDate(t.createdAt)}
{t.categoryName} — {t.replyCount} replies
)) )}
)} {/* Bug Reports Tab */} {activeTab === 'bugs' && (
{userBugs.length === 0 ? (
You haven't submitted any bug reports.{' '} Report a Bug
) : ( userBugs.map((b) => (
{b.title} {formatDate(b.createdAt)}
{b.uniqueCode} {b.status} {b.severity}
)) )}
)} {/* Password Tab */} {activeTab === 'password' && }
); } // ── Profile Tab ──────────────────────────────────────────────────────────────── function ProfileTab({ user, updateUsername }: { user: NonNullable['user']>; updateUsername: (u: string) => Promise<{ success: boolean; error?: string }> }) { const [editing, setEditing] = useState(false); const [username, setUsername] = useState(user.username); const [error, setError] = useState(''); const [saved, setSaved] = useState(false); const handleSave = useCallback(async () => { if (!username.trim()) { setError('Username cannot be empty.'); return; } if (username.length < 3) { setError('Must be at least 3 characters.'); return; } const result = await updateUsername(username.trim()); if (result.success) { setEditing(false); setSaved(true); setTimeout(() => setSaved(false), 3000); } else { setError(result.error ?? 'Failed to update username.'); } }, [username, updateUsername]); return (
{saved && (
[OK] Username updated successfully.
)}
{/* Username */}
USERNAME {editing ? (
{ setUsername(e.target.value); setError(''); }} style={{ flex: 1 }} autoFocus />
) : (
{user.username}
)}
{error &&
{error}
} {/* Static fields */} {[ { label: 'EMAIL', value: user.email }, { label: 'ROLE', value: user.role.toUpperCase() }, { label: 'MEMBER SINCE', value: formatDate(user.createdAt) }, { label: 'ADMIN', value: user.isAdmin ? 'Yes' : 'No' }, ].map(({ label, value }) => (
{label} {value}
))}
); } // ── Change Password Form ─────────────────────────────────────────────────────── function ChangePasswordForm() { const [form, setForm] = useState({ current: '', next: '', confirm: '' }); const [errors, setErrors] = useState>({}); const [loading, setLoading] = useState(false); const handleSubmit = useCallback(async (e: React.FormEvent) => { e.preventDefault(); const next: typeof errors = {}; if (!form.current) next.current = 'Current password required.'; if (!form.next) next.next = 'New password required.'; else if (form.next.length < 8) next.next = 'Must be at least 8 characters.'; if (form.next !== form.confirm) next.confirm = 'Passwords do not match.'; setErrors(next); if (Object.keys(next).length > 0) return; setLoading(true); try { await usersApi.changePassword(form.current, form.next); setForm({ current: '', next: '', confirm: '' }); setErrors({ success: 'Password changed successfully.' }); } catch (err) { setErrors({ current: err instanceof Error ? err.message : 'Failed to change password.' }); } finally { setLoading(false); } }, [form]); return (
{errors.success && (
[OK] {errors.success}
)} {[ { key: 'current' as const, label: 'Current Password', auto: 'current-password' }, { key: 'next' as const, label: 'New Password', auto: 'new-password' }, { key: 'confirm' as const, label: 'Confirm New Password', auto: 'new-password' }, ].map(({ key, label, auto }) => (
{ setForm((p) => ({ ...p, [key]: e.target.value })); setErrors((p) => ({ ...p, [key]: undefined })); }} /> {errors[key] &&
{errors[key]}
}
))}
); }