Files
nobat724_front/.claude/prompt/connect-panel-dashboard-to-api.md
T

13 KiB

اتصال پنل نماینده و داشبورد کاربر به API واقعی (حذف داده‌های mock)

پروژه

nobat724_front — سایت عمومی نوبت‌دهی. این کار صرفاً frontend است و backend (clinicpro) تغییر نمی‌کند؛ همه‌ی endpointهای لازم از قبل در clinicpro/docs/api/ مستند و آماده‌اند.

زمینه

بخش عمده‌ی سایت عمومی (لیست/جزئیات پزشک، کلینیک، بلاگ، فرایند نوبت‌گیری، پرداخت، لاگین OTP) قبلاً از طریق services/response.jsrequest.* به 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 InformationrepresentationInfo
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 — این بخش درست است و حفظ می‌شود:

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 می‌کند:

import Information from "@/data/information.json";
// ...
function Content({ children, representationInfo }) {
  // representationInfo دریافت می‌شود ولی فقط به UserDetail پاس داده می‌شود
  // Header همچنان data={Information} (mock) می‌گیرد

و app/panel/(layout)/dashboard/page.js کاملاً mock است:

import DashboardPage from "@/components/panel/dashboard";
import Information from "@/data/information.json";
function Dashboard() {
  return <DashboardPage data={Information} />;
}

داشبورد کاربر: کاملاً mock

components/dashboard/Content.js:

import userData from "@/data/userData.json";
// ...
<DashboardPage user={userData.data} ...>
  <UserAccountPage user={userData.data} ... />
</DashboardPage>

لایه‌ی API موجود (در services/response.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:

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 جدا بعد از تأیید عدم استفاده.