feat: integrate API calls for forum, bug, and event pages; replace mock data with dynamic data fetching

This commit is contained in:
Thibault Pouch
2026-03-03 09:48:07 +01:00
parent 4768bd5184
commit f54f237dd9
7 changed files with 363 additions and 241 deletions

View File

@@ -1,17 +1,29 @@
import { useState, useCallback } from 'react';
import { useState, useCallback, useEffect } from 'react';
import { useAuth } from '../../contexts/AuthContext';
import { MOCK_THREADS, MOCK_BUGS } from '../../data/mockData';
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<Tab>('profile');
const [userThreads, setUserThreads] = useState<ForumThread[]>([]);
const [userBugs, setUserBugs] = useState<BugReport[]>([]);
const userThreads = MOCK_THREADS.filter((t) => t.authorId === user?.id);
const userBugs = MOCK_BUGS.filter((b) => b.submittedById === user?.id);
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' },
@@ -121,19 +133,23 @@ export default function AccountPage() {
// ── Profile Tab ────────────────────────────────────────────────────────────────
function ProfileTab({ user, updateUsername }: { user: NonNullable<ReturnType<typeof useAuth>['user']>; updateUsername: (u: string) => void }) {
function ProfileTab({ user, updateUsername }: { user: NonNullable<ReturnType<typeof useAuth>['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(() => {
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; }
updateUsername(username.trim());
setEditing(false);
setSaved(true);
setTimeout(() => setSaved(false), 3000);
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 (
@@ -210,10 +226,15 @@ function ChangePasswordForm() {
if (Object.keys(next).length > 0) return;
setLoading(true);
await new Promise((r) => setTimeout(r, 400));
setLoading(false);
setForm({ current: '', next: '', confirm: '' });
setErrors({ success: 'Password changed successfully.' });
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 (