Files
speedBB/resources/js/pages/ForumView.jsx
2025-12-29 18:19:24 +01:00

181 lines
6.3 KiB
JavaScript

import { useEffect, useState } from 'react'
import { Button, Card, Col, Container, Form, Row } from 'react-bootstrap'
import { Link, useParams } from 'react-router-dom'
import { createThread, getForum, listForumsByParent, listThreadsByForum } from '../api/client'
import { useAuth } from '../context/AuthContext'
import { useTranslation } from 'react-i18next'
export default function ForumView() {
const { id } = useParams()
const { token } = useAuth()
const [forum, setForum] = useState(null)
const [children, setChildren] = useState([])
const [threads, setThreads] = useState([])
const [error, setError] = useState('')
const [loading, setLoading] = useState(true)
const [title, setTitle] = useState('')
const [body, setBody] = useState('')
const [saving, setSaving] = useState(false)
const { t } = useTranslation()
useEffect(() => {
let active = true
const loadData = async () => {
setLoading(true)
setError('')
try {
const forumData = await getForum(id)
if (!active) return
setForum(forumData)
const childData = await listForumsByParent(id)
if (!active) return
setChildren(childData)
if (forumData.type === 'forum') {
const threadData = await listThreadsByForum(id)
if (!active) return
setThreads(threadData)
} else {
setThreads([])
}
} catch (err) {
if (active) setError(err.message)
} finally {
if (active) setLoading(false)
}
}
loadData()
return () => {
active = false
}
}, [id])
const handleSubmit = async (event) => {
event.preventDefault()
setSaving(true)
setError('')
try {
await createThread({ title, body, forumId: id })
setTitle('')
setBody('')
const updated = await listThreadsByForum(id)
setThreads(updated)
} catch (err) {
setError(err.message)
} finally {
setSaving(false)
}
}
return (
<Container className="py-5">
{loading && <p className="bb-muted">{t('forum.loading')}</p>}
{error && <p className="text-danger">{error}</p>}
{forum && (
<>
<div className="bb-hero mb-4">
<p className="bb-chip">
{forum.type === 'forum' ? t('forum.type_forum') : t('forum.type_category')}
</p>
<h2 className="mt-3">{forum.name}</h2>
<p className="bb-muted mb-0">
{forum.description || t('forum.no_description')}
</p>
</div>
<Row className="g-4">
<Col lg={7}>
<h4 className="bb-section-title mb-3">{t('forum.children')}</h4>
{children.length === 0 && (
<p className="bb-muted">{t('forum.empty_children')}</p>
)}
{children.map((child) => (
<Card className="bb-card mb-3" key={child.id}>
<Card.Body>
<Card.Title>{child.name}</Card.Title>
<Card.Text className="bb-muted">
{child.description || t('forum.no_description')}
</Card.Text>
<Link to={`/forum/${child.id}`} className="stretched-link">
{t('forum.open')}
</Link>
</Card.Body>
</Card>
))}
{forum.type === 'forum' && (
<>
<h4 className="bb-section-title mb-3 mt-4">{t('forum.threads')}</h4>
{threads.length === 0 && (
<p className="bb-muted">{t('forum.empty_threads')}</p>
)}
{threads.map((thread) => (
<Card className="bb-card mb-3" key={thread.id}>
<Card.Body>
<Card.Title>{thread.title}</Card.Title>
<Card.Text className="bb-muted">
{thread.body.length > 160
? `${thread.body.slice(0, 160)}...`
: thread.body}
</Card.Text>
<Link to={`/thread/${thread.id}`} className="stretched-link">
{t('thread.view')}
</Link>
</Card.Body>
</Card>
))}
</>
)}
</Col>
<Col lg={5}>
<h4 className="bb-section-title mb-3">{t('forum.start_thread')}</h4>
<div className="bb-form">
{forum.type !== 'forum' && (
<p className="bb-muted mb-3">{t('forum.only_forums')}</p>
)}
{forum.type === 'forum' && !token && (
<p className="bb-muted mb-3">{t('forum.login_hint')}</p>
)}
<Form onSubmit={handleSubmit}>
<Form.Group className="mb-3">
<Form.Label>{t('form.title')}</Form.Label>
<Form.Control
type="text"
placeholder={t('form.thread_title_placeholder')}
value={title}
onChange={(event) => setTitle(event.target.value)}
disabled={!token || saving || forum.type !== 'forum'}
required
/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>{t('form.body')}</Form.Label>
<Form.Control
as="textarea"
rows={5}
placeholder={t('form.thread_body_placeholder')}
value={body}
onChange={(event) => setBody(event.target.value)}
disabled={!token || saving || forum.type !== 'forum'}
required
/>
</Form.Group>
<Button
type="submit"
variant="dark"
disabled={!token || saving || forum.type !== 'forum'}
>
{saving ? t('form.posting') : t('form.create_thread')}
</Button>
</Form>
</div>
</Col>
</Row>
</>
)}
</Container>
)
}