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

104 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# نمایش تعداد پزشکان هر تخصص در صفحه /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` از قبل تعداد را نشان می‌دهد (فقط داده ندارد):
```jsx
<p className="text-[#7E7E7E] text-[14px] font-medium">
{data.number_of_doctors} پزشک
</p>
```
`components/specialties/index.js`:
```jsx
import specialtiesData from "@/data/specialties.json";
const [filteredSpecialties, setFilteredSpecialties] = useState(specialtiesData);
const handleSearch = (value) => setFilteredSpecialties(searchOnList(specialtiesData, value, "name"));
```
`app/specialties/page.js`:
```jsx
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`
```js
getSpecialtyDoctorCounts: (cityId) =>
api.get(`api/v1/specialties/doctor-counts`, { params: { city_id: cityId } }),
```
### ۲. پاس‌دادن city id از صفحه‌ی server به کامپوننت client
در `app/specialties/page.js`:
```jsx
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 هم همه را داشت، رفتار را حفظ کن.
```jsx
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` تعداد واقعی پزشکانِ شهر زیر هر تخصص دیده شود؛ جستجو همچنان کار کند.