import { useEffect, useMemo, useState } from 'react'; import { Link } from 'react-router-dom'; import { forumApi } from '../../utils/api'; import { timeAgo } from '../../utils/format'; import type { ForumCategory, ForumThread } from '../../types'; // ── Sub-components ───────────────────────────────────────────────────────────── function CategoryCard({ category, threads }: { category: ForumCategory; threads: ForumThread[] }) { const pinned = threads.filter((t) => t.isPinned && t.categoryId === category.id); const regular = threads.filter((t) => !t.isPinned && t.categoryId === category.id); const categoryThreads = [...pinned, ...regular]; return (
{/* Category header */}
{category.icon}

{category.name}

{category.description}

{category.threadCount} threads
{/* Threads */}
{categoryThreads.length === 0 ? (
No threads yet. Be the first to post.
) : ( categoryThreads.map((thread, idx) => (
{thread.isPinned && ( Pinned )} {thread.isLocked && ( Locked )} {thread.title}
by {thread.authorName} {' '}— {timeAgo(thread.createdAt)}
{thread.replyCount}
replies
)) )}
); } // ── Forum Page ───────────────────────────────────────────────────────────────── export default function ForumPage() { const [search, setSearch] = useState(''); const [categories, setCategories] = useState([]); const [threads, setThreads] = useState([]); 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 categories; const q = search.toLowerCase(); return categories.filter((cat) => cat.name.toLowerCase().includes(q) || threads.some((t) => t.categoryId === cat.id && t.title.toLowerCase().includes(q)) ); }, [search, categories, threads]); return (
{/* Header */}
Community

FORUM

Read freely. Login to post.

{/* Search */}
setSearch(e.target.value)} style={{ width: '220px' }} aria-label="Search forum threads" />
{loading && (
Loading forum...
)} {error && !loading && (
{error}
)} {/* Categories */} {!loading && !error && ( filteredCategories.length === 0 ? (
{search.trim() ? `No results found for "${search}"` : 'No forum categories available yet.'}
) : ( filteredCategories.map((cat) => ( )) ) )}
); }