2026-02-24 20:44:16 +00:00
|
|
|
import React, { useState, useEffect } from 'react'
|
|
|
|
|
import { Link, useParams } from 'react-router-dom'
|
|
|
|
|
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 { Helmet } from 'react-helmet'
|
|
|
|
|
import { Loading } from '@/components/shared'
|
|
|
|
|
import { APP_NAME } from '@/constants/app.constant'
|
|
|
|
|
|
|
|
|
|
interface PostData {
|
|
|
|
|
image?: string
|
2026-03-11 12:20:40 +00:00
|
|
|
author?: string
|
2026-02-24 20:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 [postData, setPostData] = useState<PostData | null>(null)
|
|
|
|
|
const [loading, setLoading] = useState(true)
|
|
|
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const fetchBlogPost = async () => {
|
|
|
|
|
setLoading(true)
|
|
|
|
|
setError(null)
|
|
|
|
|
try {
|
|
|
|
|
if (id) {
|
|
|
|
|
const response = await blogService.getPostBySlug(id)
|
|
|
|
|
setBlogPost(response)
|
|
|
|
|
setPostData({
|
|
|
|
|
image: response.coverImage,
|
2026-03-11 12:20:40 +00:00
|
|
|
author: response.author,
|
2026-02-24 20:44:16 +00:00
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
setError('Blog post ID is missing.')
|
|
|
|
|
}
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
setError(error.message || 'Failed to fetch blog post.')
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fetchBlogPost()
|
|
|
|
|
}, [id])
|
|
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
|
return (
|
2026-05-26 16:09:26 +00:00
|
|
|
<div className="flex items-center justify-center min-h-screen bg-gray-50 dark:bg-gray-950">
|
2026-02-24 20:44:16 +00:00
|
|
|
<div className="text-center">
|
|
|
|
|
<Loading loading={loading} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
return (
|
2026-05-26 16:09:26 +00:00
|
|
|
<div className="min-h-screen bg-gray-50 dark:bg-gray-950 flex items-center justify-center">
|
|
|
|
|
<h1 className="text-2xl font-bold text-gray-900 dark:text-gray-100">Error: {error}</h1>
|
2026-02-24 20:44:16 +00:00
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!blogPost || !postData) {
|
|
|
|
|
return (
|
2026-05-26 16:09:26 +00:00
|
|
|
<div className="min-h-screen bg-gray-50 dark:bg-gray-950 flex items-center justify-center">
|
|
|
|
|
<h1 className="text-2xl font-bold text-gray-900 dark:text-gray-100">{translate('::Public.blog.notFound')}</h1>
|
2026-02-24 20:44:16 +00:00
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
2026-05-26 16:09:26 +00:00
|
|
|
<div className="min-h-screen bg-gray-50 dark:bg-gray-950">
|
2026-02-24 20:44:16 +00:00
|
|
|
<Helmet
|
|
|
|
|
titleTemplate={`%s | ${APP_NAME}`}
|
|
|
|
|
title={translate('::' + 'App.BlogManagement')}
|
|
|
|
|
defaultTitle={APP_NAME}
|
|
|
|
|
></Helmet>
|
|
|
|
|
<div className="relative bg-blue-900 text-white py-12"></div>
|
|
|
|
|
<div className="container mx-auto px-4">
|
|
|
|
|
<Link
|
|
|
|
|
to={ROUTES_ENUM.public.blog}
|
2026-05-26 16:09:26 +00:00
|
|
|
className="text-blue-600 hover:underline mt-4 mb-4 inline-block dark:text-blue-400"
|
2026-02-24 20:44:16 +00:00
|
|
|
>
|
|
|
|
|
← {translate('::App.BlogManagement')}
|
|
|
|
|
</Link>
|
|
|
|
|
{postData.image && (
|
|
|
|
|
<img
|
|
|
|
|
src={postData.image}
|
|
|
|
|
alt={translate('::Public.' + blogPost.title)}
|
|
|
|
|
className="w-full h-96 object-cover rounded-lg mb-8"
|
|
|
|
|
/>
|
|
|
|
|
)}
|
2026-05-26 16:09:26 +00:00
|
|
|
<h1 className="text-4xl font-bold text-gray-900 mb-6 dark:text-gray-100">
|
2026-02-24 20:44:16 +00:00
|
|
|
{translate('::Public.' + blogPost.title)}
|
|
|
|
|
</h1>
|
2026-05-26 16:09:26 +00:00
|
|
|
<div className="flex items-center text-sm text-gray-500 space-x-4 mb-8 dark:text-gray-400">
|
2026-02-24 20:44:16 +00:00
|
|
|
<div className="flex items-center">
|
2026-03-11 12:20:40 +00:00
|
|
|
<span>{postData.author}</span>
|
2026-02-24 20:44:16 +00:00
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center">
|
|
|
|
|
{blogPost.publishedAt && showDbDateAsIs(blogPost.publishedAt)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
2026-05-26 16:09:26 +00:00
|
|
|
className="prose max-w-none text-gray-800 dark:prose-invert dark:text-gray-200"
|
2026-02-24 20:44:16 +00:00
|
|
|
dangerouslySetInnerHTML={{
|
|
|
|
|
__html:
|
|
|
|
|
currentLang == 'tr'
|
|
|
|
|
? translate('::' + blogPost.contentTr!)
|
|
|
|
|
: translate('::' + blogPost.contentEn!),
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default BlogDetail
|