feat: integrate API calls for forum, bug, and event pages; replace mock data with dynamic data fetching
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { MOCK_CATEGORIES, MOCK_THREADS } from '../../data/mockData';
|
||||
import { forumApi } from '../../utils/api';
|
||||
import { timeAgo } from '../../utils/format';
|
||||
import type { ForumCategory, ForumThread } from '../../types';
|
||||
|
||||
@@ -128,15 +128,43 @@ function CategoryCard({ category, threads }: { category: ForumCategory; threads:
|
||||
|
||||
export default function ForumPage() {
|
||||
const [search, setSearch] = useState('');
|
||||
const [categories, setCategories] = useState<ForumCategory[]>([]);
|
||||
const [threads, setThreads] = useState<ForumThread[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
setLoading(true);
|
||||
|
||||
Promise.all([
|
||||
forumApi.getCategories(),
|
||||
forumApi.getThreads({ limit: 200 }),
|
||||
])
|
||||
.then(([cats, threadRes]) => {
|
||||
if (cancelled) return;
|
||||
setCategories(cats);
|
||||
setThreads(threadRes.data);
|
||||
})
|
||||
.catch(() => {
|
||||
if (cancelled) return;
|
||||
setError('Failed to load forum. Please try again.');
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) setLoading(false);
|
||||
});
|
||||
|
||||
return () => { cancelled = true; };
|
||||
}, []);
|
||||
|
||||
const filteredCategories = useMemo(() => {
|
||||
if (!search.trim()) return MOCK_CATEGORIES;
|
||||
if (!search.trim()) return categories;
|
||||
const q = search.toLowerCase();
|
||||
return MOCK_CATEGORIES.filter((cat) =>
|
||||
return categories.filter((cat) =>
|
||||
cat.name.toLowerCase().includes(q) ||
|
||||
MOCK_THREADS.some((t) => t.categoryId === cat.id && t.title.toLowerCase().includes(q))
|
||||
threads.some((t) => t.categoryId === cat.id && t.title.toLowerCase().includes(q))
|
||||
);
|
||||
}, [search]);
|
||||
}, [search, categories, threads]);
|
||||
|
||||
return (
|
||||
<div style={{ maxWidth: '960px', margin: '0 auto', padding: '4rem 1.5rem' }}>
|
||||
@@ -173,15 +201,29 @@ export default function ForumPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Categories */}
|
||||
{filteredCategories.length === 0 ? (
|
||||
{loading && (
|
||||
<div className="crt-box" style={{ padding: '2rem', textAlign: 'center', color: 'var(--color-text-muted)', fontFamily: 'var(--font-mono)' }}>
|
||||
No results found for "{search}"
|
||||
Loading forum...
|
||||
</div>
|
||||
) : (
|
||||
filteredCategories.map((cat) => (
|
||||
<CategoryCard key={cat.id} category={cat} threads={MOCK_THREADS} />
|
||||
))
|
||||
)}
|
||||
|
||||
{error && !loading && (
|
||||
<div className="crt-box" style={{ padding: '2rem', textAlign: 'center', color: 'var(--color-red)', fontFamily: 'var(--font-mono)' }}>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Categories */}
|
||||
{!loading && !error && (
|
||||
filteredCategories.length === 0 ? (
|
||||
<div className="crt-box" style={{ padding: '2rem', textAlign: 'center', color: 'var(--color-text-muted)', fontFamily: 'var(--font-mono)' }}>
|
||||
No results found for "{search}"
|
||||
</div>
|
||||
) : (
|
||||
filteredCategories.map((cat) => (
|
||||
<CategoryCard key={cat.id} category={cat} threads={threads} />
|
||||
))
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user