sozsoft-platform/ui/src/views/public/BlogDetail.tsx
2026-08-10 16:53:24 +03:00

121 lines
3.9 KiB
TypeScript

import React, { useEffect, useMemo, useState } from 'react'
import { Link, useParams } from 'react-router-dom'
import { Helmet } from 'react-helmet'
import { showDbDateAsIs } from '@/utils/dateUtils'
import { BlogPost } from '@/proxy/blog/blog'
import { blogService } from '@/services/blog.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { useStoreState } from '@/store/store'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { APP_NAME } from '@/constants/app.constant'
import { translateLabel } from './designer'
import { PublicPageLoader } from './shared'
const CenteredMessage: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<div className="flex min-h-screen items-center justify-center bg-gray-50 dark:bg-gray-950">
<h1 className="text-2xl font-bold text-gray-900 dark:text-gray-100">{children}</h1>
</div>
)
const BlogDetail: React.FC = () => {
const { id } = useParams<{ id: string }>()
const { translate } = useLocalization()
const { currentLang } = useStoreState((state) => state.locale)
const [blogPost, setBlogPost] = useState<BlogPost | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
const fetchBlogPost = async () => {
setLoading(true)
setError(null)
if (!id) {
setError(translateLabel(translate, 'Public.blog.notFound', 'Blog yazisi bulunamadi.'))
setLoading(false)
return
}
try {
setBlogPost(await blogService.getPostBySlug(id))
} catch (fetchError) {
console.error('Blog yazisi alinamadi:', fetchError)
setError(translateLabel(translate, 'Public.blog.notFound', 'Blog yazisi bulunamadi.'))
} finally {
setLoading(false)
}
}
fetchBlogPost()
// `translate` yalnizca hata metni icin kullanilir; dil degisiminde yeniden istek atilmaz.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [id])
const title = blogPost ? translate('::Public.' + blogPost.title) : ''
// Icerik anahtari yoksa `'::' + undefined` cevirisi "undefined" basiyordu.
const content = useMemo(() => {
if (!blogPost) {
return ''
}
const contentKey = currentLang === 'tr' ? blogPost.contentTr : blogPost.contentEn
return contentKey ? translate('::' + contentKey) : ''
}, [blogPost, currentLang, translate])
if (loading) {
return <PublicPageLoader />
}
if (error) {
return <CenteredMessage>{error}</CenteredMessage>
}
if (!blogPost) {
return <CenteredMessage>{translate('::Public.blog.notFound')}</CenteredMessage>
}
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-950">
<Helmet
titleTemplate={`%s | ${APP_NAME}`}
title={title || translate('::App.BlogManagement')}
defaultTitle={APP_NAME}
/>
<div className="relative bg-blue-900 py-12 text-white dark:bg-gray-950" />
<div className="container mx-auto px-4">
<Link
to={ROUTES_ENUM.public.blog}
className="mb-4 mt-4 inline-block text-blue-600 hover:underline dark:text-blue-400"
>
&larr; {translate('::App.BlogManagement')}
</Link>
{blogPost.coverImage && (
<img
src={blogPost.coverImage}
alt={title}
className="mb-8 h-96 w-full rounded-lg object-cover"
/>
)}
<h1 className="mb-6 text-4xl font-bold text-gray-900 dark:text-gray-100">{title}</h1>
<div className="mb-8 flex items-center space-x-4 text-sm text-gray-500 dark:text-gray-400">
<span>{blogPost.author}</span>
<span>{showDbDateAsIs(blogPost.publishedAt || blogPost.creationTime)}</span>
</div>
<div
className="prose max-w-none pb-12 text-gray-800 dark:prose-invert dark:text-gray-200"
dangerouslySetInnerHTML={{ __html: content }}
/>
</div>
</div>
)
}
export default BlogDetail