import { cache } from "react"; import ClinicPage from "@/components/clinic"; import Layout from "@/components/layout/StLayout"; import { notFound } from "next/navigation"; import { fetchReq } from "@/lib/req"; import { getStateInfo } from "@/lib/getStateInfo"; import { getEntityOrigin } from "@/lib/getCanonicalUrl"; import { extractEntityCityId } from "@/lib/domainHelpers"; import { isThinClinic } from "@/lib/entityQuality"; import { safeJsonLd } from "@/lib/sanitize"; import { imageUrl } from "@/helper"; const API_URL = process.env.NEXT_PUBLIC_API_URL; const getClinic = cache(async (slug) => { if (!slug || slug === "undefined") return null; const res = await fetch(`${API_URL}/api/v1/clinic/${slug}`, { next: { revalidate: 3600, tags: [`clinic-${slug}`] }, }); if (res.status === 404 || res.status === 400) return null; if (!res.ok) throw new Error(`Failed to fetch clinic: ${res.status}`); const json = await res.json(); return json?.data?.data ?? null; }); export async function generateMetadata({ params }) { const { slug } = await params; const { matchedCity } = await getStateInfo(); const siteName = matchedCity?.site_name || "نوبت 724"; const clinic = await getClinic(slug); if (!clinic) notFound(); try { const title = `${clinic.title} | ${siteName}`; const description = `رزرو نوبت و اطلاعات ${clinic.title}. مشاهده لیست پزشکان و خدمات درمانی موجود.`; const image = clinic.images_clinic?.[0]?.url ? [imageUrl(clinic.images_clinic[0].url)] : ["/assets/images/og-image.png"]; // C1-b — کلینیک به دامنهٔ شهر خودش canonical می‌شود. const origin = await getEntityOrigin(extractEntityCityId(clinic)); return { title, description, alternates: { canonical: `${origin}/clinic/${clinic.uuid}` }, // H7 — کلینیک غیرفعال/بی‌محتوا نباید ایندکس شود (تقارن با پزشک بی‌محتوا) ...(isThinClinic(clinic) && { robots: { index: false, follow: true } }), openGraph: { title, description, type: "website", images: image, }, twitter: { card: "summary_large_image", title, description, images: image, }, }; } catch (error) { console.error(`[clinic/${slug}] generateMetadata failed:`, error); return {}; } } function computeClinicRating(doctors) { const rated = doctors.filter((d) => d.point && Number(d.point) > 0); if (rated.length === 0) return null; const avg = rated.reduce((sum, d) => sum + Number(d.point), 0) / rated.length; return { "@type": "AggregateRating", ratingValue: avg.toFixed(1), ratingCount: rated.length, bestRating: "5", worstRating: "1", }; } async function Clinic({ params, searchParams }) { const { slug } = await params; const sp = await searchParams; const page = Number(sp?.page) || 1; const limit = 50; const clinic = await getClinic(slug); if (!clinic) notFound(); // همان مقصد canonical — تا url/@id و breadcrumb سیگنال متناقض ندهند. const origin = await getEntityOrigin(extractEntityCityId(clinic)); const reqDoctors = await fetchReq( `${API_URL}/api/v1/clinic/doctor-list/${slug}?page=${page}&limit=${limit}` ); const doctors = reqDoctors?.data?.data || []; const meta = reqDoctors?.data?.meta; const pagedoctors = meta ? { current: meta.currentPage, total_pages: meta.totalPages } : { current: 1, total_pages: 1 }; const aggregateRating = computeClinicRating(doctors); const specialties = [ ...new Set( doctors.flatMap((d) => d.specialties?.map((s) => s.name) ?? []) ), ].slice(0, 5); const sameAsLinks = clinic?.social_media ? Object.values(clinic.social_media).filter(Boolean) : []; const jsonLd = clinic ? { "@context": "https://schema.org", "@type": "MedicalClinic", name: clinic.title, url: `${origin}/clinic/${clinic.uuid}`, ...(clinic.images_clinic?.[0]?.url && { image: { "@type": "ImageObject", url: imageUrl(clinic.images_clinic[0].url), name: clinic.title, }, }), ...(clinic.phone && { telephone: clinic.phone }), ...(clinic.location && { address: { "@type": "PostalAddress", streetAddress: clinic.location, addressCountry: "IR", }, }), ...(clinic.map?.latitude && clinic.map?.longitude && { geo: { "@type": "GeoCoordinates", latitude: clinic.map.latitude, longitude: clinic.map.longitude, }, hasMap: `https://maps.google.com/?q=${clinic.map.latitude},${clinic.map.longitude}`, }), ...(clinic["24_7"] && { openingHoursSpecification: { "@type": "OpeningHoursSpecification", dayOfWeek: [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", ], opens: "00:00", closes: "23:59", }, }), ...(aggregateRating && { aggregateRating }), ...(specialties.length > 0 && { medicalSpecialty: specialties }), ...(sameAsLinks.length > 0 && { sameAs: sameAsLinks }), } : null; return ( <> {jsonLd && (