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

9.2 KiB
Raw Permalink Blame History

اتصال 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.jsdetailDoctor/index.jscards/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، تجمیع امتیاز را بگیر:

const resRate = await axiosInstance.get(`${API_URL}/api/v1/rate/${doctor.uuid}`);
const rateAggregate = resRate?.data?.data ?? { point: 0, satisfaction: 0, averages: [] };

سپس rateAggregate را از DoctorPageDetailDoctorCommentsChart/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):
    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_iddoctor_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] هر دو باید کامپایل شوند.