// هلپرهای مشترک نگاشت «شهر ↔ دامنه» و نام نمایشی شهر. // این ماژول pure است (بدون next/headers) تا در client، server، sitemap و تست قابل import باشد. import citiesData from "@/data/city.json"; import { isRootCity } from "@/lib/rootCity"; const ROOT_DISPLAY_NAME = "ایران"; /** * دامنهٔ شهریِ متناظر با یک city_id. * رکورد ریشه (id:600 → nobat724.com) هرگز به‌عنوان «شهر» برنمی‌گردد. * @returns {string|null} مثلا "yasuj-nobat.ir" یا null */ export function findDomainByCityId(cityId) { if (cityId == null || cityId === "") return null; const id = Number(cityId); if (!Number.isFinite(id)) return null; const city = citiesData.find((c) => Number(c.id) === id); if (!city || isRootCity(city) || !city.domain) return null; return city.domain; } /** رکورد شهر بر اساس id — رکورد ریشه شهر نیست. */ export function findCityById(cityId) { if (cityId == null || cityId === "") return null; const city = citiesData.find((c) => Number(c.id) === Number(cityId)); return city && !isRootCity(city) ? city : null; } /** * نام قابل‌نمایش شهر برای H1/Title. * روی دامنهٔ ریشه نام رکورد («نوبت 724») یک برند است نه شهر — به‌جای آن «ایران». */ export function resolveCityDisplayName(cityInfo) { if (!cityInfo || isRootCity(cityInfo)) return ROOT_DISPLAY_NAME; return cityInfo.name || ROOT_DISPLAY_NAME; } /** * city_id یک موجودیت را از شکل‌های مختلف پاسخ API بیرون می‌کشد: * - کلینیک: city: [{ id }] * - پزشک: city خالی است و شهر واقعی داخل address[].city.id می‌نشیند * - بلاگ: city_id مسطح * اولین شهرِ دارای دامنهٔ اختصاصی برنده است (پزشک چند-شهری → یک شهر اصلی). */ export function extractEntityCityId(entity) { if (!entity) return null; const candidates = [ entity.city_id, ...(Array.isArray(entity.city) ? entity.city.map((c) => c?.id) : [entity.city?.id]), ...(Array.isArray(entity.address) ? entity.address.map((a) => a?.city?.id) : []), ].filter((id) => id != null); const withDomain = candidates.find((id) => findDomainByCityId(id)); return withDomain ?? candidates[0] ?? null; }