96 lines
3 KiB
TypeScript
96 lines
3 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react'
|
|
import { useParams } from 'react-router-dom'
|
|
import { PostsService } from '../posts/postsService.ts'
|
|
import SingleColumnLayout from '../../../layouts/SingleColumnLayout.tsx'
|
|
import NavBar from '../../../components/NavBar.tsx'
|
|
import AuthNavButtons from '../../auth/components/AuthNavButtons.tsx'
|
|
import PostItem from '../components/PostItem.tsx'
|
|
import NavButton from '../../../components/buttons/NavButton.tsx'
|
|
import { useTranslations } from '../../i18n/translations.ts'
|
|
import { usePostViewModel } from '../posts/usePostViewModel.ts'
|
|
import { Temporal } from '@js-temporal/polyfill'
|
|
import { useUserStore } from '../../user/user.ts'
|
|
import { PostTimeline } from '../components/PostTimeline.tsx'
|
|
import NewCommentWidget from '../components/NewCommentWidget.tsx'
|
|
|
|
interface PostPageProps {
|
|
postsService: PostsService
|
|
}
|
|
|
|
export default function PostPage({ postsService }: PostPageProps) {
|
|
const { postId } = useParams<{ postId: string }>()
|
|
const { posts, setPosts, addReaction, reactions: _reactions, removeReaction } = usePostViewModel()
|
|
const { t } = useTranslations()
|
|
const username = useUserStore((state) => state.user?.username)
|
|
const post = posts.at(0)
|
|
const reactions = (post?.postId ? _reactions[post.postId] : []) ?? []
|
|
|
|
const loadPost = useCallback(() => {
|
|
if (!postId) return
|
|
postsService.load(postId).then((post) => setPosts(post ? [post] : []))
|
|
}, [postId, postsService, setPosts])
|
|
|
|
useEffect(() => {
|
|
loadPost()
|
|
}, [loadPost])
|
|
|
|
const onAddReaction = async (emoji: string) => {
|
|
if (!username) return
|
|
if (!post) return
|
|
|
|
await postsService.addReaction(post.postId, emoji)
|
|
|
|
addReaction(post.postId, emoji, username, Temporal.Now.instant())
|
|
}
|
|
|
|
const onClearReaction = async (emoji: string) => {
|
|
if (!username) return
|
|
if (!post) return
|
|
|
|
await postsService.removeReaction(post.postId, emoji)
|
|
removeReaction(post.postId, emoji, username)
|
|
}
|
|
|
|
async function onSubmitComment(content: string) {
|
|
if (!postId) return
|
|
if (!content.trim()) return
|
|
|
|
try {
|
|
setIsSubmittingComment(true)
|
|
await postsService.addComment(postId, content)
|
|
} finally {
|
|
setIsSubmittingComment(false)
|
|
}
|
|
|
|
loadPost()
|
|
}
|
|
|
|
const [isSubmittingComment, setIsSubmittingComment] = useState(false)
|
|
|
|
return (
|
|
<SingleColumnLayout
|
|
navbar={
|
|
<NavBar>
|
|
<NavButton to={{ pathname: '/' }}>{t('nav.home')}</NavButton>
|
|
<AuthNavButtons />
|
|
</NavBar>
|
|
}
|
|
>
|
|
<main className="w-full max-w-3xl mx-auto">
|
|
{post && (
|
|
<div className="w-full">
|
|
<PostItem
|
|
post={post}
|
|
reactions={reactions}
|
|
addReaction={onAddReaction}
|
|
clearReaction={onClearReaction}
|
|
hideViewButton={true}
|
|
/>
|
|
<PostTimeline reactions={reactions} comments={post.comments} />
|
|
<NewCommentWidget onSubmit={onSubmitComment} isSubmitting={isSubmittingComment} />
|
|
</div>
|
|
)}
|
|
</main>
|
|
</SingleColumnLayout>
|
|
)
|
|
}
|