feat: Revert homepage changes, fix Persian slug 404, and make various article and about us adjustments

- Removed the newly added city-focused section from the homepage.
- Fixed 404 error for Persian slugs in specialties and blog pages by implementing a decode helper.
- Removed the "مخصوص شهر" label from article headers.
- Linked article tags to their respective filter pages.
- Adjusted related content images to prevent distortion.
- Added a section in the "About Us" page for physician registration guidance.
- Updated the logo in the "About Us" header to the correct version.
- Added tests for the new functionality and ensured existing tests are updated accordingly.
This commit is contained in:
hamed
2026-08-08 21:06:48 +03:30
parent e8a073cae6
commit 9cfbd2e002
18 changed files with 704 additions and 145 deletions
+2 -35
View File
@@ -1,4 +1,4 @@
// متن مقدمهٔ یکتای صفحات لیست (/doctors و /clinics).
// متن مقدمهٔ یکتای صفحهٔ لیست /clinics.
// canonical درست، محتوای یکسان را غیرتکراری نمی‌کند — این متن همان نقش مکمل را دارد.
// مثل صفحات تخصص، ساختار جمله‌بندی هر شهر با هش نام شهر انتخاب می‌شود تا ۳۵ دامنه
// ۳۵ متن با ساختار متفاوت داشته باشند، نه یک قالب با نام جای‌گذاری‌شده.
@@ -21,38 +21,6 @@ const CLINIC_INTROS = (city) => [
`مرکز درمانی مناسب در ${city} را از این فهرست پیدا کنید. هر مرکز صفحهٔ اختصاصی دارد و آنچه آنجا می‌بینید از رکورد خودِ مرکز می‌آید: خدمات، تخصص‌ها، بیمه‌های طرف قرارداد و پزشکانی که پذیرش دارند. موقعیت روی نقشه هم هست تا پیش از مراجعه مسیر و زمان رسیدن را بدانید. نوبت‌گیری از صفحهٔ مرکز و از طریق پزشک انجام می‌شود؛ هزینهٔ خدمت پیش از تأیید نمایش داده می‌شود. لغو نوبت از حساب کاربری ممکن است و بازهٔ لغوشده همان لحظه به فهرست نوبت‌های آزاد برمی‌گردد. برای محدود کردن فهرست می‌توانید از فیلتر تخصص استفاده کنید تا فقط مراکزی بمانند که خدمت موردنظرتان را ارائه می‌دهند. نشانی و شمارهٔ تماس هر مرکز دوره‌ای بازبینی می‌شود.`,
];
// مقدمهٔ صفحهٔ اصلی هر دامنهٔ شهری.
//
// صفحهٔ اصلی تا پیش از این فقط `site_name` و `slogan` را از city.json شهری می‌کرد و
// بقیهٔ صفحه — بنر، کادر جستجو، جستجوهای پرتکرار، فوتر — روی همهٔ دامنه‌ها یکسان بود.
// اندازه‌گیری: شباهت متن رندرشدهٔ بهبهان و یاسوج ۹۹٫۰٪. گوگل canonicalِ درستِ ما را رد
// می‌کرد و صفحهٔ اصلی شهر را با دامنهٔ دیگری تجمیع می‌کرد
// (Duplicate, Google chose different canonical than user).
//
// عدد پزشک و تخصص داخل متن می‌آید تا تمایز فقط لفظی نباشد؛ هر شهر آمار خودش را دارد.
const CITY_INTROS = (city, doctorCount, topSpecialty) => [
`${doctorCount} پزشک از ${city} روی این سامانه پروفایل دارند. بیشترین‌شان ${topSpecialty}‌اند. نام پزشک یا نام تخصص را در کادر بالا بزنید؛ هر دو جست‌وجو می‌شوند. اگر هنوز نمی‌دانید سراغ کدام تخصص بروید، فهرست تخصص‌های همین شهر پایین‌تر آمده و از هر کدام مستقیم به پزشکانش می‌رسید.`,
`نوبت پزشکان ${city} را از همین‌جا می‌گیرید، در هر ساعت شبانه‌روز و بدون تماس با مطب. الان ${doctorCount} پزشک ثبت شده‌اند و ${topSpecialty} پرمراجعه‌ترین حوزه است. روی پروفایل هر پزشک، محل پذیرش و بازه‌های خالی همان هفته را می‌بینید. انتخاب کنید و تأیید بگیرید؛ پیامک تأییدیه همان لحظه می‌آید.`,
`اینجا نقطهٔ شروع برای پیدا کردن پزشک در ${city} است. ${doctorCount} پروفایل ثبت شده و ${topSpecialty} بیشترین سهم را دارد. هر پروفایل تخصص، نشانی محل پذیرش و امتیاز بیمارانی که قبلاً از همین‌جا نوبت گرفته‌اند را نشان می‌دهد. رزرو، تغییر و لغو نوبت همه از حساب کاربری خودتان انجام می‌شود.`,
`${city} روی این سامانه ${doctorCount} پزشک دارد و ${topSpecialty} از بقیه پرمراجعه‌تر است. کادر جست‌وجو نام پزشک و نام تخصص را با هم می‌گیرد. اگر ترجیح می‌دهید اول مرکز درمانی را انتخاب کنید، فهرست کلینیک‌ها جداست و پزشکان هر مرکز را کنار هم نشان می‌دهد.`,
`دنبال پزشک در ${city} می‌گردید؟ ${doctorCount} پزشک ثبت شده‌اند، بیشترشان در حوزهٔ ${topSpecialty}. نتیجهٔ جست‌وجو نشانی مطب، ساعات کاری و اولین نوبت آزاد هر پزشک را نشان می‌دهد. پزشکی که فعلاً نوبت‌دهی‌اش خاموش است هم می‌ماند، فقط با برچسب مشخص، تا بدانید گزینه هست.`,
`فهرست پزشکان ${city} الان ${doctorCount} پروفایل دارد و ${topSpecialty} صدرنشین مراجعه‌هاست. اطلاعات هر پزشک — تخصص، محل پذیرش، ساعت کاری — دوره‌ای بازبینی می‌شود تا با وضعیت واقعی مطب بخواند. نوبت با تأیید شما قطعی می‌شود و اگر برنامه‌تان عوض شد، لغوش از همان حساب ممکن است.`,
];
/**
* مقدمهٔ یکتای صفحهٔ اصلی یک شهر.
*
* seed از نام شهر می‌آید، نه تصادفی: متن باید بین شهرها واگرا شود ولی برای یک شهر
* در هر rebuild ثابت بماند، وگرنه محتوای صفحهٔ اصلی مدام عوض می‌شد.
*/
export function buildCityIntro(cityName, doctorCount = 0, topSpecialty = "") {
const count = Number(doctorCount) > 0 ? Number(doctorCount) : 0;
const specialty = topSpecialty || "پزشکی عمومی";
return pick(CITY_INTROS(cityName, count, specialty), hash(cityName) >>> 5);
}
/**
* جملهٔ آماری که به انتهای متن می‌چسبد.
*
@@ -60,8 +28,7 @@ export function buildCityIntro(cityName, doctorCount = 0, topSpecialty = "") {
* می‌شوند. برای آن جفت‌ها متن تقریباً یکسان می‌شد و دو صفحه دوباره شبیه هم — سنجیده
* شد: بهبهان و یاسوج روی /clinics از ۶۸٫۹٪ به ۸۴٫۷٪ شباهت رفتند.
*
* عدد واقعیِ هر شهر این را می‌شکند، چون هیچ دو شهری آمار یکسان ندارند. همان الگویی
* که در متن صفحهٔ اصلی جواب داد.
* عدد واقعیِ هر شهر این را می‌شکند، چون هیچ دو شهری آمار یکسان ندارند.
*/
const countSentence = (count, cityName, noun) =>
Number(count) > 0