From 4c8377f43915f0baf5264547eff5b32bee80d12a Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Sun, 19 Jul 2026 15:40:24 +0330 Subject: [PATCH] feat: add doctorTitle helper function and update references in metadata and FAQ --- app/doctor/[slug]/page.js | 12 ++++++------ helper/index.js | 7 +++++++ lib/specialtyContent.js | 4 +++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/doctor/[slug]/page.js b/app/doctor/[slug]/page.js index 2286550..7793998 100644 --- a/app/doctor/[slug]/page.js +++ b/app/doctor/[slug]/page.js @@ -9,7 +9,7 @@ import { buildDoctorFaq } from "@/lib/specialtyContent"; import { isThinDoctor } from "@/lib/entityQuality"; import specialtiesData from "@/data/specialties.json"; import { safeJsonLd } from "@/lib/sanitize"; -import { imageUrl } from "@/helper"; +import { imageUrl, doctorTitle } from "@/helper"; const API_URL = process.env.NEXT_PUBLIC_API_URL; const FALLBACK_IMG = "/assets/images/og-image.png"; @@ -71,14 +71,14 @@ export async function generateMetadata({ params }) { try { const specialtyNames = doctor.specialties?.map((s) => s.name).join(" و ") || ""; - const title = `دکتر ${doctor.name}${specialtyNames ? " | " + specialtyNames : ""} | ${siteName}`; + const title = `${doctorTitle(doctor.name)}${specialtyNames ? " | " + specialtyNames : ""} | ${siteName}`; const detailText = (doctor.detail || "") .replace(/<[^>]*>/g, "") .replace(/\s+/g, " ") .trim(); const description = ( detailText || - `رزرو نوبت آنلاین دکتر ${doctor.name}${specialtyNames ? " متخصص " + specialtyNames : ""}${doctor.address ? " | " + doctor.address : ""}`.trim() + `رزرو نوبت آنلاین ${doctorTitle(doctor.name)}${specialtyNames ? " متخصص " + specialtyNames : ""}${doctor.address ? " | " + doctor.address : ""}`.trim() ).slice(0, 160); const image = imageUrl(doctor.img?.[0]?.url) || FALLBACK_IMG; // C1-b — پزشک به دامنهٔ شهر خودش canonical می‌شود، روی هر دامنه‌ای که سرو شود. @@ -172,7 +172,7 @@ async function Doctor({ params }) { "@context": "https://schema.org", "@type": "Physician", "@id": `${origin}/doctor/${doctor.uuid}#physician`, - name: `دکتر ${doctor.name}`, + name: doctorTitle(doctor.name), url: `${origin}/doctor/${doctor.uuid}`, ...(specialtyNames && { medicalSpecialty: specialtyNames }), ...(doctor.img?.[0]?.url && { @@ -212,7 +212,7 @@ async function Doctor({ params }) { ...(bookableAddresses.length > 0 && { workLocation: bookableAddresses.map((addr) => ({ "@type": "MedicalClinic", - name: addr.clinic_name || addr.name || `مطب دکتر ${doctor.name}`, + name: addr.clinic_name || addr.name || `مطب ${doctorTitle(doctor.name)}`, address: { "@type": "PostalAddress", streetAddress: addr.address, @@ -254,7 +254,7 @@ async function Doctor({ params }) { itemListElement: [ { "@type": "ListItem", position: 1, name: "خانه", item: origin }, { "@type": "ListItem", position: 2, name: specialtyLabel, item: specialtyItem }, - { "@type": "ListItem", position: 3, name: `دکتر ${doctor.name}` }, + { "@type": "ListItem", position: 3, name: doctorTitle(doctor.name) }, ], } : null; diff --git a/helper/index.js b/helper/index.js index f6b6198..6d013c2 100644 --- a/helper/index.js +++ b/helper/index.js @@ -46,6 +46,13 @@ export const imageUrl = (url, fallback = "/assets/images/user.png") => { return url; }; +// نام پزشک با پیشوند «دکتر»، بدون تکرار. بعضی رکوردها خودشان با «دکتر»/«دکتر.» +// ذخیره شده‌اند؛ بدون این نرمال‌سازی خروجی «دکتر دکتر ...» می‌شود. +export const doctorTitle = (name) => { + const clean = (name || "").trim().replace(/^(دکتر|دكتر)[.،:]?\s+/, ""); + return clean ? `دکتر ${clean}` : ""; +}; + export const convertToJalali = (date) => { const currentDate = date; diff --git a/lib/specialtyContent.js b/lib/specialtyContent.js index da3774e..e95f684 100644 --- a/lib/specialtyContent.js +++ b/lib/specialtyContent.js @@ -7,6 +7,8 @@ // متفاوت استفاده می‌شود که با هشِ (تخصص، شهر) انتخاب می‌شوند — خروجی پایدار // (بین دو رندر تغییر نمی‌کند) ولی بین صفحات مختلف واگراست. +import { doctorTitle } from "@/helper"; + function hash(...parts) { const key = parts.join("|"); let value = 0; @@ -63,7 +65,7 @@ export function buildSpecialtyIntro(specialtyName, cityName, doctorCount = 0) { /** سوالات متداول صفحهٔ پزشک — منبع مشترک بلوک بصری و FAQPage schema. */ export function buildDoctorFaq(doctorName, specialtyName, cityName) { - const who = `دکتر ${doctorName}`; + const who = doctorTitle(doctorName); return [ { question: `چگونه از ${who} نوبت بگیرم؟`,