2026-02-24 20:44:16 +00:00
|
|
|
|
import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'
|
|
|
|
|
|
import { useStoreState } from '@/store/store'
|
|
|
|
|
|
import React, { useState, useEffect } from 'react'
|
|
|
|
|
|
import { useForumData } from './useForumData'
|
|
|
|
|
|
import { ForumView } from './forum/ForumView'
|
|
|
|
|
|
import { Container } from '@/components/shared'
|
|
|
|
|
|
import { Helmet } from 'react-helmet'
|
|
|
|
|
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
|
|
|
|
|
import { APP_NAME } from '@/constants/app.constant'
|
2026-03-30 20:40:20 +00:00
|
|
|
|
import { Button } from '@/components/ui'
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
|
|
|
|
|
export function Forum() {
|
|
|
|
|
|
const { translate } = useLocalization()
|
|
|
|
|
|
|
|
|
|
|
|
const { user } = useStoreState((state) => state.auth)
|
|
|
|
|
|
const {
|
|
|
|
|
|
categories,
|
|
|
|
|
|
topics,
|
|
|
|
|
|
posts,
|
|
|
|
|
|
loading,
|
|
|
|
|
|
error,
|
|
|
|
|
|
createTopic,
|
|
|
|
|
|
createPost,
|
|
|
|
|
|
likePost,
|
|
|
|
|
|
unlikePost,
|
|
|
|
|
|
clearError,
|
|
|
|
|
|
} = useForumData()
|
|
|
|
|
|
|
|
|
|
|
|
const [selectedCategory, setSelectedCategory] = useState<ForumCategory | null>(null)
|
|
|
|
|
|
const [selectedTopic, setSelectedTopic] = useState<ForumTopic | null>(null)
|
|
|
|
|
|
const [forumViewState, setForumViewState] = useState<'categories' | 'topics' | 'posts'>(
|
|
|
|
|
|
'categories',
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
|
|
|
|
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
document.addEventListener('keydown', handleKeyDown)
|
|
|
|
|
|
return () => document.removeEventListener('keydown', handleKeyDown)
|
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (error) {
|
|
|
|
|
|
const timer = setTimeout(() => {
|
|
|
|
|
|
clearError()
|
|
|
|
|
|
}, 5000)
|
|
|
|
|
|
return () => clearTimeout(timer)
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [error, clearError])
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<Container>
|
|
|
|
|
|
<Helmet
|
|
|
|
|
|
titleTemplate={`%s | ${APP_NAME}`}
|
|
|
|
|
|
title={translate('::' + 'App.Forum')}
|
|
|
|
|
|
defaultTitle={APP_NAME}
|
|
|
|
|
|
></Helmet>
|
|
|
|
|
|
|
|
|
|
|
|
{error && (
|
|
|
|
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
|
|
|
|
|
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative">
|
|
|
|
|
|
<strong className="font-bold">Error: </strong>
|
|
|
|
|
|
<span className="block sm:inline">{error}</span>
|
2026-03-30 20:40:20 +00:00
|
|
|
|
<Button onClick={clearError} className="absolute top-0 bottom-0 right-0 px-4 py-3">
|
2026-02-24 20:44:16 +00:00
|
|
|
|
<span className="sr-only">Dismiss</span>×
|
2026-03-30 20:40:20 +00:00
|
|
|
|
</Button>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
<ForumView
|
|
|
|
|
|
categories={categories}
|
|
|
|
|
|
topics={topics}
|
|
|
|
|
|
posts={posts}
|
|
|
|
|
|
loading={loading}
|
|
|
|
|
|
onCreateTopic={(topicData) => createTopic(topicData).then(() => {})}
|
|
|
|
|
|
onCreatePost={(postData) => createPost(postData).then(() => {})}
|
|
|
|
|
|
onLikePost={(id) => likePost(id).then(() => {})}
|
|
|
|
|
|
onUnlikePost={(id) => unlikePost(id).then(() => {})}
|
|
|
|
|
|
currentUserId={user.id}
|
|
|
|
|
|
currentUserName={user.name}
|
|
|
|
|
|
selectedCategory={selectedCategory}
|
|
|
|
|
|
selectedTopic={selectedTopic}
|
|
|
|
|
|
viewState={forumViewState}
|
|
|
|
|
|
onCategorySelect={setSelectedCategory}
|
|
|
|
|
|
onTopicSelect={setSelectedTopic}
|
|
|
|
|
|
onViewStateChange={setForumViewState}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Container>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default Forum
|