diff --git a/.claude/prompt/fix-dashboard-uuid-and-lists.md b/.claude/prompt/fix-dashboard-uuid-and-lists.md new file mode 100644 index 0000000..c59ffe6 --- /dev/null +++ b/.claude/prompt/fix-dashboard-uuid-and-lists.md @@ -0,0 +1,135 @@ +# رفع باگ‌های داشبورد کاربر: کوکی uuid اشتباه، URL غلط نوبت‌ها/پرداخت‌ها، و crash هدر + +## پروژه + +`nobat724_front` — سایت عمومی. **بعد از پرامپت backend اجرا شود.** + +> **Cross-repo:** تب پرداخت‌ها به endpoint جدید backend وابسته است: +> `GET /api/v1/my/payments` (در `clinicpro/.claude/prompt/my-payments-list-endpoint.md`). + +## زمینه + +داشبورد کاربر چند خطای ۴۰۴ و یک crash می‌دهد: + +1. **پروفایل ۴۰۴ (server-side):** `app/dashboard/page.js` پروفایل را با `cookieStore.get("uuid")` می‌گیرد، اما کوکی `uuid` هنگام لاگین با **uuid اوتی‌پی (send-code)** ست شده، نه uuid کاربر. پس `GET /user-profile/{otp-uuid}` ۴۰۴ می‌دهد (نه با پروفایل match می‌شود نه با کاربر). +2. **crash هدر:** `components/dashboard/userAccount/Head.js` مقدار `userInfo.realName` را روی نتیجه‌ی `getParsedUserInfo()` می‌خواند که ممکن است `null` باشد → «Cannot read properties of null (reading 'realName')». +3. **نوبت‌های من ۴۰۴:** `getMyAppointments(userId)` به `appointment/my-appointments/{userId}` می‌زند که **route ناموجود** است. route درست: `GET /api/v1/my/appointments` (کاربر از توکن). +4. **تراکنش‌ها ۴۰۴:** `getMyPayments(userId)` به `payment/my-payments/{userId}` می‌زند که **وجود ندارد** → با endpoint جدید `GET /api/v1/my/payments` جایگزین می‌شود. + +## ریشه‌ی اصلی کوکی `uuid` + +در `components/register/verificationPage/SendReq.js`، مقدار `uuid` که ست می‌شود **uuid اوتی‌پی** (از `send-code`) است، نه uuid کاربر. uuid واقعی کاربر در کوکی `userInfo` (`res.data.uuid` از userinfo) موجود است. + +```js +// SendReq.js — handleSetCookie +Cookies.set("uuid", uuid, { ... }); // ❌ uuid اوتی‌پی، نه uuid کاربر +``` + +## فایل‌های مرتبط + +| فایل | نقش | +|------|-----| +| `components/register/verificationPage/SendReq.js` | ست‌کردن کوکی `uuid` هنگام لاگین — باید uuid کاربر شود | +| `app/dashboard/page.js` | fetch پروفایل server-side با کوکی `uuid` | +| `components/dashboard/userAccount/Head.js` | `userInfo.realName` بدون گارد null | +| `services/response.js` | `getMyAppointments`, `getMyPayments` — URLهای غلط | +| `components/dashboard/userAccount/sidebars/turns/index.js` | مصرف `getMyAppointments` | +| `components/dashboard/userAccount/sidebars/transactions/index.js` | مصرف `getMyPayments` | + +## وضعیت فعلی (کد واقعی) + +### `services/response.js` — URLهای ناموجود + +```js +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 }), +``` + +### `app/dashboard/page.js` + +```js +const uuid = cookieStore.get("uuid")?.value; // ❌ uuid اوتی‌پی +profile = await fetchReq(`${API_URL}/api/v1/user-profile/${uuid}`, { headers: { Authorization: `Bearer ${token.value}` } }); +``` + +### `Head.js` + +```js +const userInfo = getParsedUserInfo(); +// ... +{userInfo.realName} // ❌ اگر null → crash +``` + +## وظایف + +### ۱. کوکی `uuid` = uuid کاربر (`SendReq.js`) + +- در `handleSetCookie`، به‌جای ست‌کردن `uuid` اوتی‌پی، uuid واقعی کاربر را ست کن. چون `getInfo` بعداً پروفایل/userinfo را می‌گیرد، بهترین جا برای ست‌کردن `uuid` کاربر **داخل `getInfo`** است بعد از دریافت `res.data.uuid`: + +```js +const getInfo = (token, cookieOptions) => { + request.getUserInfo({ headers: { Authorization: `Bearer ${token}` } }) + .then((res) => { + const profile = res?.data; + if (profile?.uuid) { + Cookies.set("uuid", profile.uuid, cookieOptions); // ✅ uuid کاربر (overwrite uuid اوتی‌پی) + Cookies.set("userInfo", JSON.stringify({ ...profile, username: profile.mobile_number }), cookieOptions); + // ... redirect / setStep ... + } + }); +}; +``` + +> کوکی `uuid` در `handleSetCookie` با uuid اوتی‌پی ست می‌شود؛ این خط را یا حذف کن یا بگذار و در `getInfo` با uuid کاربر overwrite کن (overwrite ساده‌تر است). نتیجه: کوکی نهایی `uuid` = uuid کاربر. + +### ۲. گارد null در `Head.js` + +```js +const userInfo = getParsedUserInfo() || {}; +// ... +{userInfo?.realName || "کاربر"} +``` + +- اگر `user` (prop از `buildPatientUser`) هم اطلاعات دارد، می‌توانی به‌جای کوکی از `user.name` استفاده کنی؛ ولی حداقل گارد null اجباری است تا crash نشود. + +### ۳. اصلاح URLها در `services/response.js` + +```js +getMyAppointments: (params) => api.get(`api/v1/my/appointments`, { params, requireAuth: true }), +getMyPayments: (params) => api.get(`api/v1/my/payments`, { params, requireAuth: true }), +``` + +- امضای تابع `userId` را حذف کن (کاربر از توکن می‌آید). همه‌ی callerها را به‌روز کن. + +### ۴. به‌روزرسانی callerها (turns + transactions) + +- در `sidebars/turns/index.js` و `sidebars/transactions/index.js`: `userId` را حذف کن، فقط `params` بفرست: + +```js +const response = await request.getMyAppointments(params); // turns +const response = await request.getMyPayments(params); // transactions +``` + +- شکل پاسخ paginated است (`paginated()` در backend): items از `response?.data` و total از `response?.meta?.totalRecords`/`totalPages`. کد فعلی `response.page.totalPages` می‌خواند — با شکل واقعی (`meta`) هم‌خوان کن: + +```js +if (Array.isArray(response?.data)) { + setAppointments(response.data); // یا setPayments + setTotalPages(response?.meta?.totalPages || 1); +} +``` + +> **قرارداد دقیق پاسخ را از پرامپت/داک backend بگیر** (`docs/api/payment.md` و `docs/api/appointment.md` بخش my/*). اگر `my/appointments` برای نقش کاربرِ ساده خالی برمی‌گرداند، با backend چک کن کدام endpoint نوبت‌های خود بیمار را می‌دهد (شاید `GET /api/v1/appointments/user`). **اگر مبهم بود متوقف شو و بپرس.** + +### ۵. (در صورت لزوم) `app/dashboard/page.js` + +- حالا که کوکی `uuid` = uuid کاربر است، `fetchReq(/user-profile/{uuid})` با endpoint اصلاح‌شده‌ی backend (resolve با user-uuid + lazy-create) ۲۰۰ می‌دهد. تأیید کن `buildPatientUser(profile)` با شکل پاسخ (`{success, data:{data:{...}}}` → `profile.data.data`) هم‌خوان است؛ اگر `buildPatientUser` از `profile?.data` می‌خواند ولی پاسخ دوبار تودرتو است، عمق استخراج را اصلاح کن. + +## نکات مهم + +- **وابستگی cross-repo:** تب تراکنش‌ها به `GET /api/v1/my/payments` جدید نیاز دارد؛ اگر نبود اول backend را اجرا کن. +- **امنیت/درستی:** endpointهای `my/*` کاربر را از توکن می‌گیرند؛ دیگر `userId` در URL نفرست. +- **شکل پاسخ:** `paginated()` → `data` آرایه، `meta.totalRecords`/`meta.totalPages`. این با `success(['data'=>...])` (دوبار تودرتو) فرق دارد — هرکدام را درست مصرف کن. +- **کوکی uuid:** بعد از این تغییر، همه‌ی مصرف‌کننده‌های کوکی `uuid` (dashboard/page.js, SubmitData.js, lib/auth.js) uuid کاربر می‌گیرند — درست. +- RTL/Jalali/multi-domain حفظ شوند؛ توهم‌سازی داده نکن (لیست خالی = پیام «موردی نیست»). +- **تست:** `npm run build`؛ سپس دستی با کاربر `09210651788`: داشبورد بدون ۴۰۴/crash لود شود؛ هدر نام کاربر یا «کاربر» را نشان دهد؛ تب نوبت‌ها و تراکنش‌ها بدون خطا (لیست خالی یا واقعی). سپس commit. diff --git a/components/dashboard/userAccount/Head.js b/components/dashboard/userAccount/Head.js index 2846bb6..0d6ff9f 100644 --- a/components/dashboard/userAccount/Head.js +++ b/components/dashboard/userAccount/Head.js @@ -4,14 +4,15 @@ import { getParsedUserInfo } from "@/helper"; import Image from "next/image"; function Head({ user }) { - const userInfo = getParsedUserInfo(); + const userInfo = getParsedUserInfo() || {}; + const displayName = userInfo.realName || user?.name || "کاربر"; return (

- {userInfo.realName}{" "} + {displayName}{" "} عزیز!