Files
nobat724_front/.claude/prompt/rating-rich-ui-wiring.md
hamedandClaude Opus 4.8 7d65239615 feat(doctor): wire rich rating/review UI to multi-dimensional API
Connect the existing doctor-page review UI to the rebuilt backend contract
(see clinicpro feat/rating-multidimensional).

- page.js fetches the rating aggregate alongside comments and passes
  rateAggregate down to the chart (point / satisfaction / 5 dimensions).
- Submit form sends the five dimensions with doctor_uuid; comment/reply
  send {doctor_uuid, comment, parent}; 401/403 ERR_RATING_NOT_ELIGIBLE
  surface friendly guidance.
- Like/dislike call POST /like/{uuid} with value and update from the
  response; replies render nested.
- ModalAnswer gates the submit button on GET /rate/{uuid}/eligibility.
- services/response.js: getRateEligibility, postCommentsLike(uuid, value),
  drop unused patchDoctorRate. Fix hardcoded modal title; empty-state for
  no comments. Remove orphaned AnswerField.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 00:26:20 +03:30

98 lines
9.2 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.
# اتصال UI غنیِ نظرات/امتیاز صفحه پزشک به قرارداد جدید بک‌اند
## پروژه
`nobat724_front` (سایت عمومی).
> **Cross-repo:** این پرامپت به قرارداد غنیِ بک‌اند وابسته است که در `clinicpro/.claude/prompt/rating-multidimensional-and-rich-comments.md` تعریف شده. **آن پرامپت بک‌اند باید اول اجرا شود.**
## زمینه
UI غنیِ نظرات/امتیاز صفحه پزشک (چارت ۵‌بُعدی + دایره‌ی رضایت + ستاره‌ی کلی + نظرات با نام/عکس/لایک/دیسلایک/پاسخ) از قبل در کد وجود دارد و باید **حفظ** شود. این کامپوننت‌ها فیلدهایی می‌خوانند که بک‌اندِ ساده‌ی قبلی نمی‌داد؛ حالا بک‌اند قرارداد غنی را تأمین می‌کند و فرانت فقط باید درست به آن وصل شود (و چند نقص جزئی رفع شود).
> هشدار: یک تلاش قبلی این UI را به‌اشتباه «ساده‌سازی» کرد و سپس به HEAD برگردانده شد. UI غنی نباید ساده شود؛ فقط به قرارداد جدید وصل شود.
## قرارداد بک‌اند (مرجع — از پرامپت همتا)
- `GET /api/v1/rate/{uuid}` (عمومی) → `{ data: { point, satisfaction, averages:[{name,label,progress}] } }`
- `POST /api/v1/rate` (AUTH) ← `{ doctor_uuid, waiting_time_at_clinic, accuracy_of_diagnosis, doctor_behavior, clinic_cleanliness, doctor_expertise }` (هر کدام ۰–۱۰۰)
- `GET /api/v1/comments/{uuid}` (عمومی) → `{ data: { data: [ { uuid, comment, created, parent, author:{real_name,picture:[{url}]}, like_status:{like_count,dislike_count,current_user_like:{like,dislike}}, replies:[…] } ] } }`
- `POST /api/v1/comment` (AUTH) ← `{ doctor_uuid, comment, parent }`
- `POST /api/v1/like/{commentUuid}` (AUTH) ← `{ value: 1|-1 }``{ data: { like_count, dislike_count, current_user_like } }`
- `GET /api/v1/rate/{uuid}/eligibility` (AUTH) → `{ data: { eligible: bool } }` (قبلاً اضافه شده)
- گارد بک‌اند: ثبت نظر/امتیاز فقط برای کاربرِ دارای نوبت confirmed در ۳۰ روز گذشته → در غیر این صورت `403 ERR_RATING_NOT_ELIGIBLE`.
## فایل‌های مرتبط (UI موجود که باید وصل شود)
| فایل | نقش | اصلاح موردنیاز |
|---|---|---|
| `app/doctor/[slug]/page.js` | fetch server-side | علاوه بر comments، تجمیع امتیاز از `GET /rate/{uuid}` را fetch کن و به‌صورت prop بده |
| `components/doctor/index.js``detailDoctor/index.js``cards/comments/index.js` | زنجیره prop | `rateAggregate` (point/satisfaction/averages) را عبور بده |
| `cards/comments/chart/index.js` | چارت ۵‌بُعدی + ستاره | به‌جای `doctor.point/satisfaction/average_rate.averages` از prop `rateAggregate` بخوان |
| `cards/comments/chart/ProgressAll.js` | دایره‌ی رضایت | `satisfaction` را از `rateAggregate` بگیرد |
| `cards/comments/modal/ModalAnswer.js` | مودال ثبت | پیش‌بارگذاری امتیاز قبلی را حذف/سازگار کن؛ eligibility بررسی شود |
| `cards/comments/modal/content/index.js` | هدر مودال | عنوان hardcoded «دکتر مهران امینی» → `doctor?.name` |
| `cards/comments/modal/content/Form.js` | ثبت امتیاز+نظر | body امتیاز را با `doctor_uuid` بفرست (نه `doctor_id`)؛ مدیریت ۴۰۳/۴۰۱ |
| `app/component/comment/ItemUser.js` | رندر نظر | `data.created`→تاریخ، author/like_status/replies حفظ؛ لایک/دیسلایک به `postCommentsLike(uuid, value)` وصل شود |
| `app/component/comment/SendAnswer.js` | ثبت پاسخ | body را با `doctor_uuid` و `parent` بفرست |
| `services/response.js` | wrappers | `postDoctorRate` بدنه‌ی چندبُعدی؛ `postCommentsLike(uuid, value)`؛ `getRateEligibility` (موجود) |
## وظایف
### ۱. fetch تجمیع امتیاز در صفحه و عبور prop
در `app/doctor/[slug]/page.js` کنار fetch فعلیِ doctor/comments، تجمیع امتیاز را بگیر:
```jsx
const resRate = await axiosInstance.get(`${API_URL}/api/v1/rate/${doctor.uuid}`);
const rateAggregate = resRate?.data?.data ?? { point: 0, satisfaction: 0, averages: [] };
```
سپس `rateAggregate` را از `DoctorPage``DetailDoctor``Comments``Chart`/`ProgressAll` عبور بده.
### ۲. اتصال چارت به قرارداد جدید (`chart/index.js` + `ProgressAll.js`)
- `Chart` به‌جای `doctor?.average_rate?.averages` از `rateAggregate.averages` استفاده کند (همان شکل `{name,label,progress}` که `ProgressDetail` انتظار دارد).
- `امتیاز کلی کاربران: {rateAggregate.point} از ۵` و ستاره `value={rateAggregate.point}`.
- `{rateAggregate.satisfaction}% رضایت کاربران` و `ProgressAll` با `satisfaction={rateAggregate.satisfaction}`.
- ساختار/استایل و کامپوننت‌های `ProgressDetail`/`ProgressAll`/loadingها حفظ شوند.
### ۳. فرم ثبت امتیاز چندبُعدی (`Form.js` + `ModalAnswer.js` + `content/index.js`)
- ساختار ۵‌بُعدیِ موجود (`Rates` + `ProgressChange` + `comment.rate`) حفظ شود.
- body امتیاز با **`doctor_uuid`** ارسال شود (نه `doctor_id`):
```jsx
request.postDoctorRate({
doctor_uuid: doctor.uuid,
waiting_time_at_clinic: rate[0].progress,
accuracy_of_diagnosis: rate[1].progress,
doctor_behavior: rate[2].progress,
clinic_cleanliness: rate[3].progress,
doctor_expertise: rate[4].progress,
});
```
(ترتیب ایندکس‌ها را با `progress_detail.json` تطبیق بده — همان مپ فعلیِ Form.)
- نظر با `doctor_uuid` ارسال شود: `postDoctorComment({ doctor_uuid: doctor.uuid, comment, parent: null })`.
- چون بک‌اند upsert است، `patchDoctorRate`/`defaultRate` لازم نیست؛ همیشه `postDoctorRate`.
- عنوان مودال hardcoded → `doctor?.name`.
- در `ModalAnswer`، اگر pre-load امتیاز قبلی مشکل‌ساز است حذفش کن (بک‌اند endpoint «امتیاز کاربر فعلی» ندارد؛ `getDoctorRate` حالا تجمیع برمی‌گرداند نه رأی کاربر) — فرم با مقدار اولیه‌ی صفر باز شود.
- مدیریت خطا: ۴۰۱ → «برای ثبت باید وارد شوید»؛ ۴۰۳ با `ERR_RATING_NOT_ELIGIBLE` → پیام واجد بودن؛ سایر → خطای عمومی. (با `alert`)
### ۴. لایک/دیسلایک واقعی (`ItemUser.js` + `services/response.js`)
- `postCommentsLike` را به `(commentUuid, value)` تغییر بده: `api.post(`api/v1/like/${uuid}`, { value }, { requireAuth: true })`.
- در `ItemUser`، هنگام کلیک لایک `value=1` و دیسلایک `value=-1` بفرست؛ از پاسخ `{like_count,dislike_count,current_user_like}` state محلی را به‌روز کن (به‌جای دستکاری دستیِ فعلی روی `data.like_status`).
- نمایش author/created/replies حفظ شود.
### ۵. ثبت پاسخ (`SendAnswer.js`)
- body را `{ doctor_uuid: doctor.uuid /* یا از data */, comment, parent: data.uuid }` کن (نه `doctor_id`).
- منبع `doctor.uuid` را در این کامپوننت بررسی کن؛ اگر در دسترس نیست، از prop عبور بده.
### ۶. wrapperها (`services/response.js`)
- `postDoctorRate(data)` → `POST api/v1/rate` با `requireAuth` (بدنه‌ی چندبُعدی؛ بدون تغییر امضا، فقط دیتای جدید).
- `getRateEligibility(uuid)` (موجود) حفظ شود.
- `getDoctorRate(uuid)` حالا تجمیع برمی‌گرداند — مصرف‌کننده‌ها (chart) باید `data.point/...` بخوانند.
## نکات مهم
- **UI غنی حفظ شود؛ ساده نکن.** فقط به قرارداد جدید وصل کن و نقص‌های جزئی (hardcode، `doctor_id`→`doctor_uuid`، toggle لایک) را رفع کن.
- `app/component/comment/*` بین صفحه پزشک و بلاگ مشترک است، اما فراخوانی آن در بلاگ (`components/blog/detail/index.js`) کامنت‌اوت است؛ پس تغییرات صفحه پزشک بلاگ را نمی‌شکند — ولی هنگام تغییر `ItemUser`/`Comment` این اشتراک را در نظر بگیر و چیزی که build بلاگ را بشکند وارد نکن.
- `current_user_like` در لیست عمومی همیشه false است (طبق تصمیم بک‌اند)؛ وضعیت واقعی پس از کلیک از پاسخ `toggleLike` می‌آید — UI را optimistic نگه‌دار.
- نظرات نیازمند تأیید ادمین‌اند؛ لیست لوکال ممکن است خالی باشد → empty-state، نه خطا.
- App Router + RTL + Vazir؛ کتابخانه‌ی جدید اضافه نکن.
- بعد از تغییر: `npm run build` بدون خطا؛ `/doctor/[slug]` و `/blog/[slug]` هر دو باید کامپایل شوند.