13 KiB
اتصال پنل نماینده و داشبورد کاربر به API واقعی (حذف دادههای mock)
پروژه
nobat724_front — سایت عمومی نوبتدهی. این کار صرفاً frontend است و backend (clinicpro) تغییر نمیکند؛ همهی endpointهای لازم از قبل در clinicpro/docs/api/ مستند و آمادهاند.
زمینه
بخش عمدهی سایت عمومی (لیست/جزئیات پزشک، کلینیک، بلاگ، فرایند نوبتگیری، پرداخت، لاگین OTP) قبلاً از طریق services/response.js → request.* به API واقعی متصل است. اما دو ناحیه هنوز روی دادهی mock محلی کار میکنند و عملاً برای همهی کاربران یک دادهی ثابت و ساختگی نشان میدهند:
- پنل نماینده (
app/panel/(layout)/*) — ازdata/information.jsonتغذیه میشود (نام، آمار، نمودار درآمد، لیست نوبت پزشکان). - داشبورد/حساب کاربری بیمار (
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 — این بخش درست است و حفظ میشود:
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:Informationmock فقط برای نمایش هدر استفاده میشود → باrepresentationInfoجایگزین کن.
۵. داشبورد/حساب کاربری بیمار با دادهی واقعی
components/dashboard/Content.js:
import userData from "@/data/userData.json"را حذف کن.uuidکاربر را از کوکی بخوان (یا از proplogged/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 جدا بعد از تأیید عدم استفاده.