Sectioned layout (insurance & price / services / payment / summary), base+supplementary insurance selects auto-filling visit price and discount from insurance-pricing, live cost breakdown, unified تومان unit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
90 lines
5.5 KiB
Markdown
90 lines
5.5 KiB
Markdown
# بازطراحی UI/UX مودال «ثبت مراجعه جدید»
|
|
|
|
## پروژه
|
|
|
|
`clinicpro` (admin frontend)
|
|
|
|
## زمینه
|
|
|
|
مودال «ثبت مراجعه جدید» در صفحهی پرونده بیمار، UX ضعیفی دارد: فیلدها بدون گروهبندی، label و input بدون فاصلهی منطقی، بخش خدمات و خلاصهی قیمت بیسازمان، و ارتباط بین «قیمت ویزیت / تخفیف بیمه پایه / تخفیف مکمل» با بیمهی واقعی بیمار مشخص نیست. (تصویر فعلی توسط کاربر ارائه شده.)
|
|
|
|
## مشکل / هدف
|
|
|
|
بازطراحی مودال با اصول UI/UX حرفهای:
|
|
|
|
- گروهبندی منطقی: «بیمه و مبلغ» / «خدمات» / «پرداخت و یادداشت» / «خلاصه»
|
|
- انتخاب بیمهی پایه و مکمل بهصورت select (از بیمههای entity)، و **پرکردن خودکار قیمت ویزیت و تخفیف/سهم** بر اساس قیمتگذاری بیمهی پروفایل (خروجی پرامپت `insurance-visit-pricing.md`)
|
|
- نمایش زندهی محاسبه: آزاد → با بیمه پایه → با بیمه مکمل → مبلغ نهایی
|
|
- واحد پول یکدست (تومان یا ریال — یکی، نه مخلوط؛ الان «ریال» در ورودی و «تومان» در خلاصه مخلوط است)
|
|
- فاصلهگذاری، عنوان بخشها، حالتهای loading/disabled درست
|
|
|
|
## فایلهای مرتبط
|
|
|
|
| فایل | نقش |
|
|
|------|-----|
|
|
| `assets/admin/pages/MyPatientsPage.tsx` | مودال `sessionModal` (حدود خط ۸۰۹ به بعد) و `handleSubmitSession` |
|
|
| `assets/admin/components/ui/Modal.tsx` | کامپوننت مودال (props: `size` = sm/md/lg/xl) |
|
|
| `assets/admin/components/ui/SearchableSelect.tsx` | select قابلجستجو (برای بیمه/خدمات) |
|
|
| `assets/admin/lib/utils.ts` | `formatRial`, `formatNumber` |
|
|
| `src/Patient/Controller/PatientController.php` | endpoint `POST /api/v1/patient/{uuid}/session` |
|
|
| `src/Patient/Service/PatientService.php` | محاسبهی نهایی سمت سرور |
|
|
|
|
## وضعیت فعلی
|
|
|
|
- اسکیمای فرم:
|
|
|
|
```tsx
|
|
const sessionSchema = z.object({
|
|
visit_price_rials: z.coerce.number().min(0),
|
|
base_insurance_discount_percent: z.coerce.number().min(0).max(100),
|
|
supplementary_discount_percent: z.coerce.number().min(0).max(100),
|
|
payment_method: z.enum(["cash", "card", "insurance", "online", "pending"]),
|
|
notes: z.string().optional(),
|
|
});
|
|
```
|
|
|
|
- محاسبهی قیمت سمت کلاینت:
|
|
|
|
```tsx
|
|
function calcFinalPrice(visitPrice, baseDiscount, suppDiscount, servicesTotal) {
|
|
const afterBase = visitPrice * (1 - baseDiscount / 100);
|
|
const afterSupp = afterBase * (1 - suppDiscount / 100);
|
|
return Math.round(afterSupp) + servicesTotal;
|
|
}
|
|
```
|
|
|
|
- خلاصهی پایین مودال «جمع خدمات» و «مبلغ نهایی» را با «تومان» نشان میدهد ولی ورودیها «ریال» هستند — ناهماهنگ.
|
|
- backend (`PatientService::createSession`) همین فیلدها + `insurance_base_id` / `insurance_supplementary_id` را میپذیرد (موجودیت `PatientSession` این دو ستون را دارد) اما فرم فعلی آنها را ارسال نمیکند.
|
|
|
|
## وظایف
|
|
|
|
### ۱. ساختار بصری مودال
|
|
|
|
مودال را به بخشهای واضح با عنوان تقسیم کن (میتوانی `size="lg"` بدهی):
|
|
|
|
1. **بیمه و مبلغ ویزیت**: select بیمهی پایه + select بیمهی مکمل + قیمت ویزیت + تخفیف/سهم
|
|
2. **خدمات**: انتخاب بخش/سرویس + chipهای انتخابشده (الگوی فعلی، فقط منظمتر)
|
|
3. **پرداخت و یادداشت**: روش پرداخت + یادداشت
|
|
4. **خلاصه**: آزاد / با بیمه پایه / با بیمه مکمل / جمع خدمات / مبلغ نهایی
|
|
|
|
### ۲. اتصال بیمه به قیمتگذاری پروفایل
|
|
|
|
- بیمههای entity و قیمتگذاری را از endpoint پرامپت `insurance-visit-pricing.md` (`GET /api/v1/insurance-pricing`) بگیر.
|
|
- با انتخاب بیمهی پایه/مکمل، قیمت ویزیت آزاد و سهم بیمار خودکار پر شود (کاربر بتواند دستی override کند).
|
|
- `insurance_base_id` و `insurance_supplementary_id` را در body ارسال کن (backend از قبل پشتیبانی میکند).
|
|
|
|
### ۳. واحد پول یکدست
|
|
|
|
همهجا یک واحد. توصیه: نمایش به تومان با `formatRial` اگر این util تومان میدهد را بررسی کن؛ ورودی و خلاصه باید یکی باشند.
|
|
|
|
### ۴. تست
|
|
|
|
`ddev exec npx tsc --noEmit` و `ddev exec yarn dev`؛ بدون خطا.
|
|
|
|
## نکات مهم
|
|
|
|
- وابسته به `insurance-visit-pricing.md`؛ اگر آن endpoint هنوز نیست، حداقل ساختار UI و select بیمهها از `GET /api/v1/insurances` را پیاده کن و auto-fill را با TODO علامت بزن.
|
|
- فرم با React Hook Form + Zod؛ server state با TanStack Query.
|
|
- از کامپوننتهای `ui/` موجود استفاده کن؛ کتابخانهی CSS جدید اضافه نکن؛ RTL.
|
|
- این تغییر صرفاً frontend است؛ تغییر API لازم نیست (مگر اینکه فیلد بیمهی session در پاسخ کم باشد).
|