forked from UKSOURCE/hailearning.edu.vn
131 lines
4.1 KiB
TypeScript
131 lines
4.1 KiB
TypeScript
import Link from "next/link";
|
|
import type { Metadata } from "next";
|
|
import Breadcrumb from "@/app/components/Breadcrumb";
|
|
import NewsDetailsSection from "./components/NewsDetailsSection";
|
|
import { fetchBlogList, fetchBlogDetail } from "@/api/blogsApi";
|
|
import Sidebar from "@/app/blog/components/Sidebar";
|
|
import { getCmsImageUrl } from "@/utils";
|
|
|
|
// Generate static params for all blog posts
|
|
export async function generateStaticParams() {
|
|
try {
|
|
const blogResponse = await fetchBlogList({ page: 1, limit: 100 });
|
|
return blogResponse.data.blogs.map((post) => ({
|
|
slug: post.slug,
|
|
}));
|
|
} catch (error) {
|
|
console.error("Error generating static params:", error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
interface BlogDetailsPageProps {
|
|
params:
|
|
| Promise<{
|
|
slug: string;
|
|
}>
|
|
| {
|
|
slug: string;
|
|
};
|
|
}
|
|
|
|
// SEO metadata cho từng bài blog (Open Graph / thumbnail khi share)
|
|
export async function generateMetadata({
|
|
params,
|
|
}: {
|
|
params:
|
|
| Promise<{
|
|
slug: string;
|
|
}>
|
|
| {
|
|
slug: string;
|
|
};
|
|
}): Promise<Metadata> {
|
|
const resolvedParams = params instanceof Promise ? await params : params;
|
|
const slug = resolvedParams.slug;
|
|
|
|
try {
|
|
const blogResponse = await fetchBlogDetail(slug);
|
|
const post = blogResponse.data;
|
|
|
|
const apiUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3001";
|
|
const url = `${apiUrl}/blog/${post.slug}`;
|
|
const imageUrl = post.featuredImage
|
|
? getCmsImageUrl(post.featuredImage)
|
|
: `${apiUrl}/assets/img/inner-page/news-details/details-1.jpg`;
|
|
|
|
return {
|
|
title: post.title,
|
|
description: post.excerpt,
|
|
openGraph: {
|
|
title: post.title,
|
|
description: post.excerpt,
|
|
url,
|
|
type: "article",
|
|
images: [
|
|
{
|
|
url: imageUrl,
|
|
alt: post.title,
|
|
},
|
|
],
|
|
},
|
|
twitter: {
|
|
card: "summary_large_image",
|
|
title: post.title,
|
|
description: post.excerpt,
|
|
images: [imageUrl],
|
|
},
|
|
};
|
|
} catch {
|
|
return {
|
|
title: "Blog Details",
|
|
};
|
|
}
|
|
}
|
|
|
|
export default async function BlogDetailsPage({ params }: BlogDetailsPageProps) {
|
|
// Handle both Promise and direct object
|
|
const resolvedParams = params instanceof Promise ? await params : params;
|
|
const slug = resolvedParams.slug;
|
|
|
|
// Fetch blog detail from API
|
|
let blogResponse;
|
|
try {
|
|
blogResponse = await fetchBlogDetail(slug);
|
|
} catch {
|
|
return (
|
|
<>
|
|
<Breadcrumb title="Blog Details" current="Blog Details" />
|
|
<section className="news-standard-section section-padding fix">
|
|
<div className="container">
|
|
<div className="news-standard-wrapper">
|
|
<div className="row g-4">
|
|
<div className="col-lg-8 col-12">
|
|
<div className="py-5">
|
|
<h2>Post not found</h2>
|
|
<p>The blog post you are looking for does not exist.</p>
|
|
<Link href="/blog" className="theme-btn mt-3">
|
|
Back to Blog <i className="fa-solid fa-arrow-right"></i>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
{/* Sidebar on the right */}
|
|
<Sidebar />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</>
|
|
);
|
|
}
|
|
|
|
const post = blogResponse.data;
|
|
|
|
return (
|
|
<>
|
|
<Breadcrumb title={post.title} current="Blog Details" />
|
|
<NewsDetailsSection post={post} />
|
|
</>
|
|
);
|
|
}
|