82 lines
2.0 KiB
TypeScript
82 lines
2.0 KiB
TypeScript
import type { Metadata } from 'next';
|
|
import BlogPostContent from './BlogPostContent';
|
|
|
|
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000';
|
|
|
|
async function fetchPostMeta(slug: string) {
|
|
try {
|
|
const res = await fetch(`${API_BASE_URL}/api/v1/blog/${slug}`, {
|
|
cache: 'no-store',
|
|
});
|
|
if (!res.ok) return null;
|
|
return res.json() as Promise<{
|
|
title: string;
|
|
excerpt: string;
|
|
metaTitle?: string;
|
|
metaDescription?: string;
|
|
primaryKeyword?: string;
|
|
secondaryKeywords?: string[];
|
|
coverImageUrl?: string;
|
|
authorName: string;
|
|
publishedAt?: string;
|
|
updatedAt: string;
|
|
}>;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function generateMetadata({
|
|
params,
|
|
}: {
|
|
params: { slug: string; locale: string };
|
|
}): Promise<Metadata> {
|
|
const post = await fetchPostMeta(params.slug);
|
|
|
|
if (!post) {
|
|
return { title: 'Blog — Xpeditis' };
|
|
}
|
|
|
|
const title = post.metaTitle || post.title;
|
|
const description = post.metaDescription || post.excerpt;
|
|
const keywords = [post.primaryKeyword, ...(post.secondaryKeywords ?? [])]
|
|
.filter(Boolean)
|
|
.join(', ');
|
|
const coverImage = post.coverImageUrl
|
|
? post.coverImageUrl.startsWith('http')
|
|
? post.coverImageUrl
|
|
: `${API_BASE_URL}${post.coverImageUrl}`
|
|
: undefined;
|
|
|
|
return {
|
|
title,
|
|
description,
|
|
keywords: keywords || undefined,
|
|
openGraph: {
|
|
title,
|
|
description,
|
|
type: 'article',
|
|
publishedTime: post.publishedAt,
|
|
authors: [post.authorName],
|
|
images: coverImage ? [{ url: coverImage, alt: post.title }] : [],
|
|
},
|
|
twitter: {
|
|
card: 'summary_large_image',
|
|
title,
|
|
description,
|
|
images: coverImage ? [coverImage] : [],
|
|
},
|
|
alternates: {
|
|
canonical: `/blog/${params.slug}`,
|
|
},
|
|
};
|
|
}
|
|
|
|
export default function BlogPostPage({
|
|
params,
|
|
}: {
|
|
params: { slug: string; locale: string };
|
|
}) {
|
|
return <BlogPostContent slug={params.slug} />;
|
|
}
|