import type { Metadata } from "next"; import { getLocale, getTranslations } from "next-intl/server"; import { notFound } from "next/navigation"; import { Container } from "@/components/layout/container"; import { PageHero } from "@/components/layout/page-hero"; import { PortfolioCategoryFilter } from "@/components/site/portfolio-category-filter"; import { PortfolioProjectDetail } from "@/components/site/portfolio-project-detail"; import { PortfolioProjectGrid } from "@/components/site/portfolio-project-grid"; import { JsonLd } from "@/components/seo/json-ld"; import { getSeoSettings, getSiteSettings } from "@/lib/app-config"; import { buildLocalizedMetadata, buildProjectJsonLd } from "@/lib/metadata"; import { resolveLocale } from "@/lib/locale"; import { getActivePortfolioCategories, getLocalizedValue, getPublishedPortfolioProjects, resolvePortfolioSlug, } from "@/lib/portfolio"; type PortfolioSlugPageProps = { params: Promise<{ locale: string; slug: string; }>; }; export const dynamic = "force-dynamic"; export async function generateMetadata({ params }: PortfolioSlugPageProps): Promise { const { slug } = await params; const siteSettings = await getSiteSettings(); const localeKey = resolveLocale(await getLocale().catch(() => siteSettings.defaultLocale), siteSettings.defaultLocale); const resolved = await resolvePortfolioSlug(slug); if (!resolved) { const t = await getTranslations({ locale: localeKey, namespace: "portfolioPage" }); return await buildLocalizedMetadata({ locale: localeKey, pathname: `/portfolio/${slug}`, title: t("title"), description: t("intro"), }); } if (resolved.kind === "category") { const t = await getTranslations({ locale: localeKey, namespace: "portfolioPage" }); return await buildLocalizedMetadata({ locale: localeKey, pathname: `/portfolio/${slug}`, title: getLocalizedValue(resolved.category.name, localeKey), description: getLocalizedValue(resolved.category.description, localeKey) || t("intro"), }); } return await buildLocalizedMetadata({ locale: localeKey, pathname: `/portfolio/${slug}`, title: getLocalizedValue(resolved.project.title, localeKey), description: getLocalizedValue(resolved.project.summary, localeKey), image: resolved.project.coverImagePath, type: "article", publishedTime: resolved.project.publishedAt, }); } export default async function PortfolioSlugPage({ params }: PortfolioSlugPageProps) { const { slug } = await params; const siteSettings = await getSiteSettings(); const localeKey = resolveLocale(await getLocale().catch(() => siteSettings.defaultLocale), siteSettings.defaultLocale); const resolved = await resolvePortfolioSlug(slug); if (!resolved) { notFound(); } if (resolved.kind === "category") { const { category } = resolved; const [categories, projects] = await Promise.all([ getActivePortfolioCategories(), getPublishedPortfolioProjects({ categorySlug: slug }), ]); const t = await getTranslations({ locale: localeKey, namespace: "portfolioPage" }); return ( <> ); } const { project: item } = resolved; const [t, seo] = await Promise.all([ getTranslations({ locale: localeKey, namespace: "portfolioDetail" }), getSeoSettings(), ]); const title = getLocalizedValue(item.title, localeKey); const category = getLocalizedValue(item.category.name, localeKey); const summary = getLocalizedValue(item.summary, localeKey); const jsonLd = buildProjectJsonLd({ settings: siteSettings, seo, locale: localeKey, pathname: `/portfolio/${slug}`, title, description: summary, image: item.coverImagePath, datePublished: item.publishedAt, genre: category, keywords: [getLocalizedValue(item.serviceLabel, localeKey), String(item.projectYear)].filter(Boolean), clientName: item.clientName, }); return ( <> ); }