From baf6e40dde6b6d7474648dbd9d4e8b79d0dd37b5 Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Fri, 5 Jun 2026 06:45:02 +0330 Subject: [PATCH] fix(templates): wire template detail page to real content service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /templates/[id] only searched the hardcoded demo catalog, so real published containers (e.g. insta-promo) 404'd even though the browser listed and linked them. Now resolveTemplate() fetches the container by slug via fetchProject(), falling back to the demo catalog, else notFound(). Page + generateMetadata made async (await params). Also fix TemplateDetailBreadcrumb: it called server-only getTranslations while rendered inside the client TemplateDetailContent tree (500 at request time) — switched to the useTranslations hook. Was latent because demo pages were static-prerendered. Co-Authored-By: Claude Opus 4.8 --- src/app/[locale]/templates/[id]/page.tsx | 31 +++++++++++++++---- .../templates/TemplateDetailBreadcrumb.tsx | 8 +++-- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/app/[locale]/templates/[id]/page.tsx b/src/app/[locale]/templates/[id]/page.tsx index f998316..c8ca660 100644 --- a/src/app/[locale]/templates/[id]/page.tsx +++ b/src/app/[locale]/templates/[id]/page.tsx @@ -2,24 +2,43 @@ import type { Metadata } from "next"; import { notFound } from "next/navigation"; import { TemplateDetailContent } from "@/components/templates/TemplateDetailContent"; -import { VIDEO_TEMPLATES_CATALOG } from "@/lib/video-templates-catalog"; +import { fetchProject } from "@/lib/admin-api"; +import { + adminProjectToCatalogTemplate, + VIDEO_TEMPLATES_CATALOG, + type VideoCatalogTemplate, +} from "@/lib/video-templates-catalog"; interface TemplateDetailPageProps { - params: { id: string }; + params: Promise<{ id: string }>; } +/** + * Resolve a template by its `[id]` route param — which is the container SLUG used + * in catalog links. Real (admin-managed) templates come from the content service + * via fetchProject(slug); the hardcoded demo catalog is the offline fallback. + */ +async function resolveTemplate(id: string): Promise { + const admin = await fetchProject(id); + if (admin) return adminProjectToCatalogTemplate(admin); + return VIDEO_TEMPLATES_CATALOG.find((item) => item.id === id) ?? null; +} + +// Pre-render the demo catalog; real container slugs render on demand (ISR). export function generateStaticParams() { return VIDEO_TEMPLATES_CATALOG.map((template) => ({ id: template.id })); } -export function generateMetadata({ params }: TemplateDetailPageProps): Metadata { - const template = VIDEO_TEMPLATES_CATALOG.find((item) => item.id === params.id); +export async function generateMetadata({ params }: TemplateDetailPageProps): Promise { + const { id } = await params; + const template = await resolveTemplate(id); if (!template) return {}; return { title: `${template.name} — FlatRender` }; } -export default function TemplateDetailPage({ params }: TemplateDetailPageProps) { - const template = VIDEO_TEMPLATES_CATALOG.find((item) => item.id === params.id); +export default async function TemplateDetailPage({ params }: TemplateDetailPageProps) { + const { id } = await params; + const template = await resolveTemplate(id); if (!template) notFound(); return (
diff --git a/src/components/templates/TemplateDetailBreadcrumb.tsx b/src/components/templates/TemplateDetailBreadcrumb.tsx index 1802c82..12fbddc 100644 --- a/src/components/templates/TemplateDetailBreadcrumb.tsx +++ b/src/components/templates/TemplateDetailBreadcrumb.tsx @@ -1,15 +1,17 @@ +"use client"; + import Link from "next/link"; import { ChevronRight } from "lucide-react"; -import { getTranslations } from "next-intl/server"; +import { useTranslations } from "next-intl"; interface TemplateDetailBreadcrumbProps { templateName: string; } -export async function TemplateDetailBreadcrumb({ +export function TemplateDetailBreadcrumb({ templateName, }: TemplateDetailBreadcrumbProps) { - const t = await getTranslations("auto.componentsTemplatesTemplateDetailBreadcrumb"); + const t = useTranslations("auto.componentsTemplatesTemplateDetailBreadcrumb"); return (