# اتصال پنل نماینده و داشبورد کاربر به 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 ; ``` اما `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 ; } ``` ### داشبورد کاربر: کاملاً mock `components/dashboard/Content.js`: ```js import userData from "@/data/userData.json"; // ... ``` ### لایه‌ی 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 می‌آید) را به `
` و `` پاس بده. - چون شکل `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 جدا بعد از تأیید عدم استفاده.