2025-06-19 21:42:16 +00:00
|
|
|
import React, { useState, useEffect } from "react";
|
|
|
|
|
import { Link, useParams } from "react-router-dom";
|
|
|
|
|
import { useLanguage } from "../context/LanguageContext";
|
|
|
|
|
import { BlogPost, blogService } from "../services/api/blog.service";
|
|
|
|
|
import { format } from "date-fns";
|
|
|
|
|
import { tr } from "date-fns/locale";
|
|
|
|
|
|
|
|
|
|
interface PostData {
|
|
|
|
|
image?: string;
|
|
|
|
|
author?: {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
avatar?: string;
|
|
|
|
|
};
|
|
|
|
|
}
|
2025-05-15 10:48:03 +00:00
|
|
|
|
|
|
|
|
const BlogDetail: React.FC = () => {
|
|
|
|
|
const { id } = useParams<{ id: string }>();
|
2025-06-22 12:44:11 +00:00
|
|
|
const { language, setLanguage, t } = useLanguage();
|
2025-06-19 21:42:16 +00:00
|
|
|
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);
|
2025-05-15 10:48:03 +00:00
|
|
|
|
2025-06-19 21:42:16 +00:00
|
|
|
useEffect(() => {
|
|
|
|
|
const fetchBlogPost = async () => {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
setError(null);
|
|
|
|
|
try {
|
|
|
|
|
if (id) {
|
|
|
|
|
const response = await blogService.getPostBySlug(id);
|
|
|
|
|
setBlogPost(response);
|
|
|
|
|
setPostData({
|
|
|
|
|
image: response.coverImage,
|
|
|
|
|
author: response.author,
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
setError("Blog post ID is missing.");
|
|
|
|
|
}
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
setError(error.message || "Failed to fetch blog post.");
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-05-15 10:48:03 +00:00
|
|
|
|
2025-06-19 21:42:16 +00:00
|
|
|
fetchBlogPost();
|
|
|
|
|
}, [id]);
|
|
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
|
|
|
|
<h1 className="text-2xl font-bold text-gray-900">Loading...</h1>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-05-15 10:48:03 +00:00
|
|
|
|
2025-06-19 21:42:16 +00:00
|
|
|
if (error) {
|
2025-05-15 10:48:03 +00:00
|
|
|
return (
|
|
|
|
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
2025-06-19 21:42:16 +00:00
|
|
|
<h1 className="text-2xl font-bold text-gray-900">Error: {error}</h1>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!blogPost || !postData) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
|
|
|
|
<h1 className="text-2xl font-bold text-gray-900">
|
|
|
|
|
{t("blog.notFound")}
|
|
|
|
|
</h1>
|
2025-05-15 10:48:03 +00:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
2025-06-19 21:42:16 +00:00
|
|
|
<div className="min-h-screen bg-gray-50 pt-32 pb-16">
|
2025-05-15 10:48:03 +00:00
|
|
|
<div className="container mx-auto px-4">
|
2025-06-19 21:42:16 +00:00
|
|
|
<Link
|
|
|
|
|
to="/blog"
|
|
|
|
|
className="text-blue-600 hover:underline mb-4 inline-block"
|
|
|
|
|
>
|
|
|
|
|
← {t("blog.backToBlog")}
|
2025-05-15 10:48:03 +00:00
|
|
|
</Link>
|
|
|
|
|
{postData.image && (
|
|
|
|
|
<img
|
2025-06-19 21:42:16 +00:00
|
|
|
src={postData.image}
|
|
|
|
|
alt={t(blogPost.title)}
|
2025-05-15 10:48:03 +00:00
|
|
|
className="w-full h-96 object-cover rounded-lg mb-8"
|
|
|
|
|
/>
|
|
|
|
|
)}
|
2025-06-19 21:42:16 +00:00
|
|
|
<h1 className="text-4xl font-bold text-gray-900 mb-6">
|
|
|
|
|
{t(blogPost.title)}
|
|
|
|
|
</h1>
|
2025-05-15 10:48:03 +00:00
|
|
|
<div className="flex items-center text-sm text-gray-500 space-x-4 mb-8">
|
|
|
|
|
<div className="flex items-center">
|
2025-06-19 21:42:16 +00:00
|
|
|
<span>{postData.author?.name}</span>
|
2025-05-15 10:48:03 +00:00
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center">
|
2025-06-19 21:42:16 +00:00
|
|
|
{blogPost.publishedAt &&
|
|
|
|
|
format(new Date(blogPost.publishedAt), "dd MMM yyyy", {
|
|
|
|
|
locale: tr,
|
|
|
|
|
})}
|
2025-05-15 10:48:03 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-06-22 12:44:11 +00:00
|
|
|
<div className="prose max-w-none text-gray-800" dangerouslySetInnerHTML={{ __html: language == "tr" ? t(blogPost.contentTr!!) : t(blogPost.contentEn!!) }} />
|
2025-05-15 10:48:03 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default BlogDetail;
|