// سیاست ایندکس صفحات فرود تخصص — منبع مشترک صفحه و sitemap تا واگرا نشوند. // // تخصصی که زیرشاخهٔ فعال دارد (مثل «داخلی» با فرزند «گوارش و کبد») یک دستهٔ سطح‌بالاست: // محتوای مستقلی ندارد و با فرزندانش روی همان کوئری رقابت می‌کند → noindex. // // اما «والد بودن» به‌تنهایی کافی نیست: تخصص‌هایی مثل «پزشک عمومی» هم parent_id تهی // دارند و هم هیچ زیرشاخه‌ای ندارند. آن‌ها در عمل برگ‌اند و صفحهٔ واقعی خدمات و // پزشکان را نشان می‌دهند، پس ایندکس می‌مانند. import specialtiesData from "@/data/specialties.json"; // فقط فرزندان فعال شمرده می‌شوند؛ زیرشاخهٔ غیرفعال صفحه‌ای ندارد که رقابت کند. const IDS_WITH_ACTIVE_CHILDREN = new Set( specialtiesData .filter((item) => item?.status === 1 && item?.parent_id != null) .map((item) => Number(item.parent_id)) ); /** دستهٔ سطح‌بالا: بدون والد، ولی دارای زیرشاخهٔ فعال. */ export function isCategorySpecialty(specialty) { if (!specialty || specialty.parent_id != null) return false; return IDS_WITH_ACTIVE_CHILDREN.has(Number(specialty.id)); } export function isIndexableSpecialty(specialty) { return Boolean(specialty) && !isCategorySpecialty(specialty); } /** زیرشاخه‌های فعالِ یک تخصص، به ترتیب weight سپس نام. */ export function childSpecialties(specialty) { if (!specialty) return []; return specialtiesData .filter( (item) => item?.status === 1 && String(item.parent_id ?? "") === String(specialty.id) ) .sort((a, b) => (a.weight ?? 0) - (b.weight ?? 0) || a.name.localeCompare(b.name, "fa")); } /** والدِ فعالِ یک زیرتخصص، یا null اگر ریشه باشد. */ export function parentSpecialty(specialty) { if (!specialty?.parent_id) return null; return ( specialtiesData.find( (item) => item?.status === 1 && String(item.id) === String(specialty.parent_id) ) ?? null ); }