import Link from "next/link"; import { getStateInfo } from "@/lib/getStateInfo"; import { fetchReq } from "@/lib/req"; import { buildCityIntro } from "@/lib/listingIntro"; import { isNoindexDoctor } from "@/lib/entityQuality"; const API_URL = process.env.NEXT_PUBLIC_API_URL; const SHOWN_SPECIALTIES = 8; const SHOWN_DOCTORS = 4; /** * بخش شهرمحور صفحهٔ اصلی — متن یکتا، آمار واقعی و تخصص‌های پرمراجعهٔ همان شهر. * * چرا لازم است: صفحهٔ اصلی تا پیش از این فقط `site_name` و `slogan` را شهری می‌کرد و * متن رندرشدهٔ دو دامنه ۹۹٫۰٪ یکسان بود. گوگل canonicalِ درستِ ما را رد می‌کرد و * صفحهٔ اصلی شهر را با دامنهٔ دیگر تجمیع می‌کرد. تمایز فقط با تگ حل نمی‌شود؛ محتوا * باید واقعاً فرق کند، و آمارِ هر شهر خودبه‌خود فرق دارد. * * جدا از FrequentSearches است: آن فهرست ثابتِ تخصص‌هاست و روی همهٔ دامنه‌ها یکی؛ این * یکی از داده‌ی همان شهر ساخته می‌شود. */ async function CityHighlights() { const { matchedCity, isRoot } = await getStateInfo(); // دامنهٔ ریشه شهر نیست؛ آمار و متن شهری آنجا معنا ندارد. if (isRoot || !matchedCity?.id) return null; const [counts, doctors] = await Promise.all([ fetchCityCounts(matchedCity.id), fetchCityDoctors(matchedCity.id), ]); if (counts.length === 0) return null; const doctorCount = counts.reduce((sum, s) => sum + s.number_of_doctors, 0); if (doctorCount === 0) return null; const top = counts.slice(0, SHOWN_SPECIALTIES); const cityName = matchedCity.name; return (

{buildCityIntro(cityName, doctorCount, top[0].name)}

تخصص‌های پرمراجعه در {cityName}

{doctors.length > 0 && ( <>

پزشکان {cityName}

)}
); } /** * تخصص‌های همان شهر که پزشک دارند، از پرپزشک به کم‌پزشک. * * خطا اینجا بلعیده می‌شود و آرایهٔ خالی برمی‌گردد: صفحهٔ اصلی مهم‌ترین صفحهٔ سایت است * و قطعیِ API نباید سفیدش کند. این همان مرز واقعیِ error handling است — یک I/O boundary. */ /** * چند پزشکِ همان شهر برای لینک مستقیم از صفحهٔ اصلی. * * بک‌اند خودش «دارای نوبت» را بالاتر مرتب می‌کند، پس ترتیب پیش‌فرض همان چیزی است که * می‌خواهیم. پروفایل noindex کنار گذاشته می‌شود — همان سیاستی که sitemap اعمال * می‌کند؛ لینک دادن از صفحهٔ اصلی به صفحه‌ای که خودمان از ایندکس بیرونش گذاشته‌ایم، * سیگنال متناقض است. */ async function fetchCityDoctors(cityId) { const data = await fetchReq( `${API_URL}/api/v1/doctors?city_id=${cityId}&limit=12` ); const items = data?.data ?? []; if (!Array.isArray(items)) return []; return items .filter((d) => !isNoindexDoctor(d)) .slice(0, SHOWN_DOCTORS) .map((d) => ({ uuid: d.uuid, name: d.name, display_name: d.display_name, specialty: d.specialties?.[0]?.name ?? null, })); } async function fetchCityCounts(cityId) { const data = await fetchReq( `${API_URL}/api/v1/specialties/doctor-counts?city_id=${cityId}` ); const items = data?.data?.data ?? []; if (!Array.isArray(items)) return []; return items .map((s) => ({ ...s, number_of_doctors: Number(s?.number_of_doctors) || 0 })) .filter((s) => s.slug && s.number_of_doctors > 0) .sort((a, b) => b.number_of_doctors - a.number_of_doctors); } export default CityHighlights;