Files
nobat724_front/.claude/prompt/fix-dashboard-uuid-and-lists.md
hamedandClaude Opus 4.8 96b1684b82 fix(dashboard): guard null userInfo in Head to stop 500 crash
getParsedUserInfo() can return null (cookie missing/unparseable), so
reading userInfo.realName crashed the dashboard with a 500. Default to
an empty object and fall back to the user prop's name or 'کاربر'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 19:15:25 +03:30

136 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# رفع باگ‌های داشبورد کاربر: کوکی 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.