import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { AgentProfileClient } from '@/components/agents/agent-profile-client'; import { JsonLd, generateAgentJsonLd, generateBreadcrumbJsonLd, } from '@/components/seo/json-ld'; import { fetchAgentProfile, fetchAgentReviews, fetchAgentListings, } from '@/lib/agents-server'; // --------------------------------------------------------------------------- // Constants // --------------------------------------------------------------------------- const siteUrl = process.env['NEXT_PUBLIC_SITE_URL'] || 'https://goodgo.vn'; // --------------------------------------------------------------------------- // Metadata (runs server-side, provides , <meta>, OG, canonical) // --------------------------------------------------------------------------- interface PageProps { params: Promise<{ locale: string; id: string }>; } export async function generateMetadata({ params: paramsPromise }: PageProps): Promise<Metadata> { const params = await paramsPromise; const agent = await fetchAgentProfile(params.id); if (!agent) { return { title: 'Không tìm thấy môi giới' }; } const title = agent.isVerified ? `${agent.fullName} — Môi giới xác minh | GoodGo` : `${agent.fullName} — Môi giới BĐS | GoodGo`; const description = [ agent.agency ? `Công ty: ${agent.agency}` : null, agent.serviceAreas.length > 0 ? `Khu vực: ${agent.serviceAreas.join(', ')}` : null, agent.totalReviews > 0 ? `Đánh giá: ${agent.avgReviewRating}/5 (${agent.totalReviews} lượt)` : null, `${agent.activeListings.length} tin đăng đang hoạt động`, `${agent.totalDeals} giao dịch thành công`, ] .filter(Boolean) .join(' | '); const canonicalUrl = `${siteUrl}/${params.locale}/agents/${params.id}`; return { title, description, alternates: { canonical: canonicalUrl, languages: { vi: `${siteUrl}/vi/agents/${params.id}`, en: `${siteUrl}/en/agents/${params.id}`, }, }, openGraph: { type: 'profile', locale: params.locale === 'vi' ? 'vi_VN' : 'en_US', url: canonicalUrl, title, description, siteName: 'GoodGo', images: agent.avatarUrl ? [{ url: agent.avatarUrl, width: 400, height: 400, alt: agent.fullName }] : [{ url: '/og-image.png', width: 1200, height: 630, alt: 'GoodGo' }], }, twitter: { card: 'summary', title, description, images: agent.avatarUrl ? [agent.avatarUrl] : ['/og-image.png'], }, }; } // --------------------------------------------------------------------------- // Page (Server Component) // --------------------------------------------------------------------------- export default async function AgentProfilePage({ params: paramsPromise }: PageProps) { const params = await paramsPromise; const [agent, reviewsResult, listingsResult] = await Promise.all([ fetchAgentProfile(params.id), fetchAgentReviews(params.id, 1, 10), fetchAgentListings(params.id, 1, 50), ]); if (!agent) { notFound(); } // Build JSON-LD structured data const agentJsonLd = generateAgentJsonLd(agent, siteUrl); const breadcrumbJsonLd = generateBreadcrumbJsonLd([ { name: 'Trang chủ', url: siteUrl }, { name: 'Môi giới', url: `${siteUrl}/${params.locale}/agents` }, { name: agent.fullName, url: `${siteUrl}/${params.locale}/agents/${params.id}` }, ]); return ( <> {/* Structured data for search engines */} <JsonLd data={agentJsonLd} /> <JsonLd data={breadcrumbJsonLd} /> {/* Interactive client component */} <AgentProfileClient agent={agent} reviews={reviewsResult.data} listings={listingsResult.data} listingsTotal={listingsResult.total} /> </> ); }