import { useEffect, useMemo, useState } from 'react' import { Badge, Container } from 'react-bootstrap' import { Link } from 'react-router-dom' import { listAllForums, listThreads } from '../api/client' import { useTranslation } from 'react-i18next' export default function Home() { const [forums, setForums] = useState([]) const [threads, setThreads] = useState([]) const [error, setError] = useState('') const [loadingForums, setLoadingForums] = useState(true) const [loadingThreads, setLoadingThreads] = useState(true) const { t } = useTranslation() useEffect(() => { listAllForums() .then(setForums) .catch((err) => setError(err.message)) .finally(() => setLoadingForums(false)) }, []) useEffect(() => { listThreads() .then(setThreads) .catch((err) => setError(err.message)) .finally(() => setLoadingThreads(false)) }, []) const getParentId = (forum) => { if (!forum.parent) return null if (typeof forum.parent === 'string') { return forum.parent.split('/').pop() } return forum.parent.id ?? null } const forumTree = useMemo(() => { const map = new Map() const roots = [] forums.forEach((forum) => { map.set(String(forum.id), { ...forum, children: [] }) }) forums.forEach((forum) => { const parentId = getParentId(forum) const node = map.get(String(forum.id)) if (parentId && map.has(String(parentId))) { map.get(String(parentId)).children.push(node) } else { roots.push(node) } }) const sortNodes = (nodes) => { nodes.sort((a, b) => { if (a.position !== b.position) return a.position - b.position return a.name.localeCompare(b.name) }) nodes.forEach((node) => sortNodes(node.children)) } sortNodes(roots) return roots }, [forums]) const forumMap = useMemo(() => { const map = new Map() forums.forEach((forum) => { map.set(String(forum.id), forum) }) return map }, [forums]) const recentThreads = useMemo(() => { return [...threads] .sort((a, b) => new Date(b.created_at) - new Date(a.created_at)) .slice(0, 12) }, [threads]) const resolveForumName = (thread) => { if (!thread?.forum) return t('portal.unknown_forum') const parts = thread.forum.split('/') const id = parts[parts.length - 1] return forumMap.get(String(id))?.name || t('portal.unknown_forum') } const resolveForumId = (thread) => { if (!thread?.forum) return null const parts = thread.forum.split('/') return parts[parts.length - 1] || null } const renderTree = (nodes, depth = 0) => nodes.map((node) => (
{node.name}
{node.description || t('forum.no_description')}
{node.children?.length > 0 && (
{renderTree(node.children, depth + 1)}
)}
)) return (
{t('portal.latest_posts')}
{loadingThreads &&

{t('home.loading')}

} {!loadingThreads && recentThreads.length === 0 && (

{t('portal.empty_posts')}

)} {!loadingThreads && recentThreads.length > 0 && (
{t('portal.topic')} {t('thread.replies')} {t('thread.views')} {t('thread.last_post')}
{recentThreads.map((thread) => (
{thread.title}
{t('thread.by')} {thread.user_name || t('thread.anonymous')} {t('portal.forum_label')}{' '} {resolveForumId(thread) ? ( {resolveForumName(thread)} ) : ( resolveForumName(thread) )}
0
{thread.created_at?.slice(0, 10) || '—'}
))}
)}
{error &&

{error}

}
) }