Files
speedBB/frontend/src/pages/ThreadView.jsx
2025-12-24 13:15:02 +01:00

114 lines
3.9 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 { createPost, getThread, listPostsByThread } from '../api/client'
import { useAuth } from '../context/AuthContext'
import { useTranslation } from 'react-i18next'
export default function ThreadView() {
const { id } = useParams()
const { token } = useAuth()
const [thread, setThread] = useState(null)
const [posts, setPosts] = useState([])
const [error, setError] = useState('')
const [loading, setLoading] = useState(true)
const [body, setBody] = useState('')
const [saving, setSaving] = useState(false)
const { t } = useTranslation()
useEffect(() => {
setLoading(true)
Promise.all([getThread(id), listPostsByThread(id)])
.then(([threadData, postData]) => {
setThread(threadData)
setPosts(postData)
})
.catch((err) => setError(err.message))
.finally(() => setLoading(false))
}, [id])
const handleSubmit = async (event) => {
event.preventDefault()
setSaving(true)
setError('')
try {
await createPost({ body, threadId: id })
setBody('')
const updated = await listPostsByThread(id)
setPosts(updated)
} catch (err) {
setError(err.message)
} finally {
setSaving(false)
}
}
return (
<Container className="py-5">
{loading && <p className="bb-muted">{t('thread.loading')}</p>}
{error && <p className="text-danger">{error}</p>}
{thread && (
<>
<div className="bb-hero mb-4">
<p className="bb-chip">{t('thread.label')}</p>
<h2 className="mt-3">{thread.title}</h2>
<p className="bb-muted mb-2">{thread.body}</p>
{thread.forum && (
<p className="bb-muted mb-0">
{t('thread.category')}{' '}
<Link to={`/forum/${thread.forum.id || thread.forum.split('/').pop()}`}>
{thread.forum.name || t('thread.back_to_category')}
</Link>
</p>
)}
</div>
<Row className="g-4">
<Col lg={7}>
<h4 className="bb-section-title mb-3">{t('thread.replies')}</h4>
{posts.length === 0 && (
<p className="bb-muted">{t('thread.empty')}</p>
)}
{posts.map((post) => (
<Card className="bb-card mb-3" key={post.id}>
<Card.Body>
<Card.Text>{post.body}</Card.Text>
<small className="bb-muted">
{post.author?.username || t('thread.anonymous')}
</small>
</Card.Body>
</Card>
))}
</Col>
<Col lg={5}>
<h4 className="bb-section-title mb-3">{t('thread.reply')}</h4>
<div className="bb-form">
{!token && (
<p className="bb-muted mb-3">{t('thread.login_hint')}</p>
)}
<Form onSubmit={handleSubmit}>
<Form.Group className="mb-3">
<Form.Label>{t('form.message')}</Form.Label>
<Form.Control
as="textarea"
rows={5}
placeholder={t('form.reply_placeholder')}
value={body}
onChange={(event) => setBody(event.target.value)}
disabled={!token || saving}
required
/>
</Form.Group>
<Button type="submit" variant="dark" disabled={!token || saving}>
{saving ? t('form.posting') : t('form.post_reply')}
</Button>
</Form>
</div>
</Col>
</Row>
</>
)}
</Container>
)
}