Files
nobat724_front/.claude/prompt/specialties-doctor-count-wire.md
hamedandClaude Opus 4.8 344285dce5 feat(specialties): show per-city doctor count on /specialties
Fetch active specialties with number_of_doctors from
GET /api/v1/specialties/doctor-counts (scoped to the current city via
matchedCity.id) instead of the static specialties.json, so each specialty
card shows the real doctor count.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 22:27:39 +03:30

5.4 KiB
Raw Permalink Blame History

نمایش تعداد پزشکان هر تخصص در صفحه /specialties

پروژه

nobat724_front (سایت عمومی).

Cross-repo: وابسته به endpoint بک‌اند GET /api/v1/specialties/doctor-counts?city_id=<id> (پرامپت clinicpro/.claude/prompt/specialty-doctor-counts.md). آن اول اجرا شود.

زمینه

صفحه‌ی /specialties کارت هر تخصص را از data/specialties.json (ثابت) رندر می‌کند و زیرش {data.number_of_doctors} پزشک می‌نویسد — اما specialties.json فیلد number_of_doctors ندارد، پس همیشه خالی است. باید تعداد واقعی پزشکانِ هر تخصص در شهرِ دامنه‌ی جاری از API گرفته و نمایش داده شود.

شهر از subdomain تشخیص داده می‌شود: server-side با getStateInfo()matchedCity.id (همان city id بک‌اند).

مشکل / هدف

صفحه به‌جای json ثابت، لیست تخصص‌ها را با number_of_doctors از endpoint جدید (با city_id شهر جاری) بگیرد و نمایش دهد.

فایل‌های مرتبط

فایل نقش
app/specialties/page.js Server Component — matchedCity.id را از getStateInfo بگیر و به صفحه بده
components/specialties/index.js "use client" — fetch count از API به‌جای json ثابت
components/specialties/list/ItemSpecialties.js نمایش data.number_of_doctors (موجود — تغییر لازم ندارد)
services/response.js افزودن wrapper getSpecialtyDoctorCounts(cityId)

وضعیت فعلی (کد واقعی)

ItemSpecialties.js از قبل تعداد را نشان می‌دهد (فقط داده ندارد):

<p className="text-[#7E7E7E] text-[14px] font-medium">
  {data.number_of_doctors} پزشک
</p>

components/specialties/index.js:

import specialtiesData from "@/data/specialties.json";
const [filteredSpecialties, setFilteredSpecialties] = useState(specialtiesData);
const handleSearch = (value) => setFilteredSpecialties(searchOnList(specialtiesData, value, "name"));

app/specialties/page.js:

function Specialties() {
  return (<Layout name="/specialties"><SpecialtiesPage /></Layout>);
}

پاسخ بک‌اند GET /api/v1/specialties/doctor-counts?city_id=<id>: { success, data: { data: [ {id, name, slug, parent_id, number_of_doctors, ...} ] } } (double-nested — success(['data'=>...])).

وظایف

۱. wrapper در services/response.js

getSpecialtyDoctorCounts: (cityId) =>
  api.get(`api/v1/specialties/doctor-counts`, { params: { city_id: cityId } }),

۲. پاس‌دادن city id از صفحه‌ی server به کامپوننت client

در app/specialties/page.js:

import { getStateInfo } from "@/lib/getStateInfo";
async function Specialties() {
  const { matchedCity } = await getStateInfo();
  return (
    <Layout name="/specialties">
      <SpecialtiesPage cityId={matchedCity?.id ?? null} />
    </Layout>
  );
}

(صفحه باید async شود؛ generateMetadata موجود دست‌نخورده.)

۳. fetch در components/specialties/index.js

  • prop cityId بگیر.
  • در useEffect (mount / تغییر cityId) request.getSpecialtyDoctorCounts(cityId) را صدا بزن، res.data.data را در state بگذار.
  • تا رسیدن داده، می‌توان از specialties.json به‌عنوان نمایش اولیه استفاده کرد (یا اسکلت)، ولی منبعِ نهایی API است.
  • جستجو روی همان لیستِ API اعمال شود (searchOnList(list, value, "name")).
  • فقط تخصص‌های ریشه (یا همان رفتار فعلی) نمایش داده شوند؛ اگر API همه را می‌دهد و قبلاً json هم همه را داشت، رفتار را حفظ کن.
const [all, setAll] = useState([]);
const [filtered, setFiltered] = useState([]);
useEffect(() => {
  request.getSpecialtyDoctorCounts(cityId)
    .then((res) => { const items = res?.data?.data ?? []; setAll(items); setFiltered(items); })
    .catch(() => { setAll([]); setFiltered([]); });
}, [cityId]);
const handleSearch = (value) => setFiltered(searchOnList(all, value, "name"));

۴. ItemSpecialties.js

بدون تغییر ساختار؛ فقط مطمئن شو data.number_of_doctors (که حالا از API می‌آید) و data.id (برای لینک /doctors?specialties=) درست‌اند. اگر number_of_doctors صفر بود، «۰ پزشک» نمایش داده شود (یا در صورت تمایل پنهان شود).

نکات مهم

  • پاسخ double-nested است → res.data.data.
  • matchedCity?.id ممکن است null باشد (دامنه‌ی ناشناخته) → بدون city_id ارسال شود؛ بک‌اند شمارش سراسری می‌دهد (fallback).
  • لینک کارت تخصص از data.id استفاده می‌کند (/doctors?specialties=<id>) — مطمئن شو id در پاسخ API همان است که /doctors با specialty_id/specialties می‌پذیرد.
  • App Router؛ generateMetadata و getStateInfo الگوی موجود؛ RTL/Vazir.
  • بعد از تغییر: npm run build بدون خطا؛ روی /specialties تعداد واقعی پزشکانِ شهر زیر هر تخصص دیده شود؛ جستجو همچنان کار کند.