165 lines
13 KiB
Markdown
165 lines
13 KiB
Markdown
# اتصال پنل نماینده و داشبورد کاربر به API واقعی (حذف دادههای mock)
|
|
|
|
## پروژه
|
|
|
|
`nobat724_front` — سایت عمومی نوبتدهی. این کار صرفاً frontend است و backend (`clinicpro`) تغییر نمیکند؛ همهی endpointهای لازم از قبل در `clinicpro/docs/api/` مستند و آمادهاند.
|
|
|
|
## زمینه
|
|
|
|
بخش عمدهی سایت عمومی (لیست/جزئیات پزشک، کلینیک، بلاگ، فرایند نوبتگیری، پرداخت، لاگین OTP) قبلاً از طریق `services/response.js` → `request.*` به API واقعی متصل است. اما دو ناحیه هنوز روی دادهی mock محلی کار میکنند و عملاً برای همهی کاربران یک دادهی ثابت و ساختگی نشان میدهند:
|
|
|
|
1. **پنل نماینده** (`app/panel/(layout)/*`) — از `data/information.json` تغذیه میشود (نام، آمار، نمودار درآمد، لیست نوبت پزشکان).
|
|
2. **داشبورد/حساب کاربری بیمار** (`components/dashboard/*`) — از `data/userData.json` و `data/bank.json` تغذیه میشود (پروفایل، نوبتها، تراکنشها).
|
|
|
|
نکتهی مهم: layout پنل (`app/panel/(layout)/layout.js`) **همین حالا** `representationInfo` واقعی را server-side از `GET /api/v1/representation/{uuid}` میگیرد و به `Content` پاس میدهد، ولی `Content` و صفحات داخلی این prop را نادیده میگیرند و بهجایش `information.json` را import میکنند. پس بخشی از کار «وصلکردن سیمهای قطعشده»ی موجود است، نه ساختن از صفر.
|
|
|
|
## مشکل / هدف
|
|
|
|
پنل نماینده و داشبورد کاربر را به API واقعی وصل کن تا دادهی هر کاربر واقعی و مخصوص خودش باشد، و importهای `data/information.json`، `data/userData.json`، `data/bank.json` از مسیر render حذف شوند.
|
|
|
|
این کار باید **مرحلهبهمرحله** انجام شود (یک قابلیت در هر مرحله: پیادهسازی → build/lint → تأیید → commit)، چون نواحی مستقلاند و ریسک رگرسیون در صفحات mock بالاست.
|
|
|
|
## فایلهای مرتبط
|
|
|
|
| فایل | نقش |
|
|
|------|-----|
|
|
| `services/response.js` | لایهی `request.*`؛ توابع موجود استفاده میشوند و توابع جدید representation dashboard اضافه میشود |
|
|
| `app/panel/(layout)/layout.js` | server-side؛ `representationInfo` را از API میگیرد و پاس میدهد (موجود — تغییر نمیکند) |
|
|
| `components/panel/Content.js` | `import Information from "@/data/information.json"` را حذف و `representationInfo` را مصرف کن |
|
|
| `app/panel/(layout)/dashboard/page.js` | mock `Information` را با دادهی واقعی representation dashboard جایگزین کن |
|
|
| `app/panel/(layout)/turns/page.js` | mock `Information` → نوبتهای واقعی |
|
|
| `app/panel/(layout)/user-account/page.js` | mock `Information` + `Bank` → دادهی واقعی نماینده + حساب بانکی |
|
|
| `app/panel/(layout)/add-doctor/page.js` | mock `Information` → `representationInfo` |
|
|
| `components/dashboard/Content.js` | `import userData from "@/data/userData.json"` را با `user-profile` + appointments واقعی جایگزین کن |
|
|
| `components/dashboard/userAccount/sidebars/turns/index.js` | از قبل `request.*` دارد — صرفاً بررسی اتصال |
|
|
| `components/dashboard/userAccount/sidebars/transactions/index.js` | از قبل `request.*` دارد — صرفاً بررسی اتصال |
|
|
| `lib/auth.js` | `getUser()` server-side از کوکی (برای uuid/representation_uuid) |
|
|
| `clinicpro/docs/api/representation.md` | قرارداد endpointهای representation و dashboard ماهانه/سالانه |
|
|
| `clinicpro/docs/api/user-profile.md` | قرارداد پروفایل کاربر |
|
|
|
|
## وضعیت فعلی
|
|
|
|
### پنل: دادهی واقعی موجود است ولی نادیده گرفته میشود
|
|
|
|
`app/panel/(layout)/layout.js` — این بخش درست است و حفظ میشود:
|
|
|
|
```js
|
|
let representationInfo = null;
|
|
// ...
|
|
representationInfo = await fetchReq(
|
|
`${API_URL}/api/v1/representation/${representationUuid}`,
|
|
{ headers: { Authorization: `Bearer ${accessToken.value}` } }
|
|
);
|
|
return <Content children={children} representationInfo={representationInfo} />;
|
|
```
|
|
|
|
اما `components/panel/Content.js` آن را مصرف نمیکند و mock import میکند:
|
|
|
|
```js
|
|
import Information from "@/data/information.json";
|
|
// ...
|
|
function Content({ children, representationInfo }) {
|
|
// representationInfo دریافت میشود ولی فقط به UserDetail پاس داده میشود
|
|
// Header همچنان data={Information} (mock) میگیرد
|
|
```
|
|
|
|
و `app/panel/(layout)/dashboard/page.js` کاملاً mock است:
|
|
|
|
```js
|
|
import DashboardPage from "@/components/panel/dashboard";
|
|
import Information from "@/data/information.json";
|
|
function Dashboard() {
|
|
return <DashboardPage data={Information} />;
|
|
}
|
|
```
|
|
|
|
### داشبورد کاربر: کاملاً mock
|
|
|
|
`components/dashboard/Content.js`:
|
|
|
|
```js
|
|
import userData from "@/data/userData.json";
|
|
// ...
|
|
<DashboardPage user={userData.data} ...>
|
|
<UserAccountPage user={userData.data} ... />
|
|
</DashboardPage>
|
|
```
|
|
|
|
### لایهی API موجود (در `services/response.js`)
|
|
|
|
این توابع از قبل آمادهاند و باید استفاده شوند:
|
|
|
|
```js
|
|
getRepresentationInfo: (uuid) => api.get(`api/v1/representation/${uuid}`, { requireAuth: true }),
|
|
getUserProfile: (uuid) => api.get(`/api/v1/user-profile/${uuid}`, { requireAuth: true }),
|
|
getMyAppointments: (userId, params) => api.get(`api/v1/appointment/my-appointments/${userId}`, { params, requireAuth: true }),
|
|
getMyPayments: (userId, params) => api.get(`api/v1/payment/my-payments/${userId}`, { params, requireAuth: true }),
|
|
```
|
|
|
|
توابع dashboard ماهانه/سالانه نماینده **هنوز نیستند** و باید اضافه شوند (endpointها در `representation.md` مستند است).
|
|
|
|
## وظایف
|
|
|
|
اجرای مرحلهبهمرحله؛ بعد از هر قابلیت `npm run lint && npm run build` و سپس commit جدا.
|
|
|
|
### ۱. افزودن توابع representation dashboard به `services/response.js`
|
|
|
|
طبق `clinicpro/docs/api/representation.md`:
|
|
|
|
```js
|
|
getRepresentationDashboardMonthly: (uuid, year, month) =>
|
|
api.get(`api/v1/representation/${uuid}/dashboard/monthly`, {
|
|
params: { year, month },
|
|
requireAuth: true,
|
|
}),
|
|
getRepresentationDashboardYearly: (uuid, year) =>
|
|
api.get(`api/v1/representation/${uuid}/dashboard/yearly`, {
|
|
params: { year },
|
|
requireAuth: true,
|
|
}),
|
|
```
|
|
|
|
> پاسخ تکمنبعی است: داده در `response.data` (پس از interceptor در `api.js` که `response.data` را برمیگرداند) → سپس `result.data` طبق envelope `{ success, data }`.
|
|
|
|
### ۲. وصلکردن Header و UserDetail پنل به `representationInfo`
|
|
|
|
در `components/panel/Content.js`:
|
|
- `import Information from "@/data/information.json"` را حذف کن.
|
|
- `representationInfo` (که از layout میآید) را به `<Header data={...} />` و `<UserDetail data={...} />` پاس بده.
|
|
- چون شکل `representationInfo` (فیلدهای `full_name`, `city_name`, `commission_percent`, `bank_account`, ...) با شکل mock (`name`, `detail`, `expertise`, `all_patients`, ...) فرق دارد، یک adapter کوچک بنویس که فیلدهای واقعی را به همان propهایی که `Header`/`UserDetail` انتظار دارند map کند. فیلدهای آماری که در API نیستند (مثل `todays_activities`) را از dashboard ماهانه پر کن یا حذف کن — توهمسازی داده ممنوع.
|
|
|
|
### ۳. صفحهی dashboard پنل با دادهی واقعی
|
|
|
|
`app/panel/(layout)/dashboard/page.js`:
|
|
- این صفحه Server Component است. `representation_uuid` را از کوکی `userInfo` بخوان (مثل `layout.js`).
|
|
- `GET /api/v1/representation/{uuid}/dashboard/monthly?year=&month=` را با سال/ماه جلالی جاری فراخوانی کن (تبدیل به سال/ماه میلادی یا طبق چیزی که backend انتظار دارد — در `representation.md` پارامتر `year`/`month` عددی است؛ بررسی کن backend جلالی میخواهد یا میلادی، اگر مبهم بود همینجا توقف کن و بپرس).
|
|
- خروجی `stats` (`total_appointments`, `total_revenue_rials`, `commission_rials`, `daily[]`) را به `DashboardPage` بده.
|
|
- نمودار درآمد (`chart_amount_income` در mock) را از `daily[].revenue` یا از dashboard سالانه (`months[].revenue_rials`) بساز.
|
|
|
|
### ۴. صفحات turns و user-account و add-doctor پنل
|
|
|
|
- `turns/page.js`: لیست نوبت پزشکانِ نماینده — اگر endpoint اختصاصی نیست، از همان dashboard ماهانه (`daily`) یا توقف و پرسش. mock حذف شود.
|
|
- `user-account/page.js`: `bank_account` واقعی از `representationInfo` بهجای `data/bank.json`؛ اطلاعات نماینده بهجای `information.json`.
|
|
- `add-doctor/page.js`: `Information` mock فقط برای نمایش هدر استفاده میشود → با `representationInfo` جایگزین کن.
|
|
|
|
### ۵. داشبورد/حساب کاربری بیمار با دادهی واقعی
|
|
|
|
`components/dashboard/Content.js`:
|
|
- `import userData from "@/data/userData.json"` را حذف کن.
|
|
- `uuid` کاربر را از کوکی بخوان (یا از prop `logged`/`getUser`).
|
|
- پروفایل را با `request.getUserProfile(uuid)` بگیر (طبق `user-profile.md`).
|
|
- نوبتها و تراکنشها از قبل در `sidebars/turns/index.js` و `sidebars/transactions/index.js` با `request.getMyAppointments` / `request.getMyPayments` گرفته میشوند — صرفاً تأیید کن که `userId` درست پاس میشود و دیگر به `userData.json` وابسته نیستند.
|
|
- فیلدهای mock که معادل API ندارند را حذف کن (نه ساختن دادهی جعلی).
|
|
|
|
## نکات مهم
|
|
|
|
- **هیچ تغییری در backend لازم نیست.** اگر حین کار به endpoint غایبی برخوردی (مثلاً «لیست نوبت پزشکان یک نماینده»)، **متوقف شو و بپرس** — پرامپت جداگانه برای backend لازم میشود (cross-repo)؛ دادهی جعلی جایگزین نکن.
|
|
- **App Router:** صفحات پنل/داشبورد که دادهی server-side میخواهند باید Server Component بمانند و کوکی را با `cookies()` از `next/headers` بخوانند؛ کامپوننتهای `"use client"` که `request.*` صدا میزنند uuid را بهصورت prop بگیرند. همیشه `await params`/`await cookies()`.
|
|
- **Auth:** همهی این endpointها `requireAuth` میخواهند؛ توابع `request.*` خودشان کوکی `access_token` را بهصورت Bearer ضمیمه میکنند. در 401، `api.js` بهصورت خودکار logout و redirect به `/login` میکند — رفتار موجود را خراب نکن.
|
|
- **Multi-domain:** این صفحات هم زیر subdomain شهر اجرا میشوند؛ هر `matchedCity`/`getStateInfo` موجود را حذف نکن.
|
|
- **شکل پاسخ:** envelope بکاند `{ success, data }` است. interceptor در `services/api.js` یکبار `response.data` را برمیگرداند، پس در فراخوانیها دادهی واقعی در `result.data` است. این را با یک endpoint واقعی تأیید کن، نه با حدس.
|
|
- **Jalali/RTL:** تاریخها با `jalali-moment`/`dayjs` به شمسی نمایش داده شوند؛ مبالغ به ریال با جداکنندهی هزارگان فارسی. timestampهای API یونیکس هستند.
|
|
- **adapter جدا:** برای هر ناحیه یک تابع map کوچک بنویس (API → propهای کامپوننت موجود) تا کامپوننتهای نمایشی دستنخورده بمانند و دیف کوچک شود.
|
|
- **تست:** بعد از هر قابلیت `npm run lint` و `npm run build`؛ build کامل خطاهای صفحه/متادیتا را آشکار میکند. سپس commit با پیام توصیفی فارسی/انگلیسی برای همان قابلیت.
|
|
- **فایلهای mock:** فعلاً فایلهای `data/*.json` را پاک نکن؛ فقط importشان را از مسیر render حذف کن (ممکن است جای دیگری مرجع داشته باشند). حذف نهایی فایلها در یک commit جدا بعد از تأیید عدم استفاده.
|