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>
5.5 KiB
5.5 KiB
بازطراحی 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 |
محاسبهی نهایی سمت سرور |
وضعیت فعلی
- اسکیمای فرم:
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(),
});
- محاسبهی قیمت سمت کلاینت:
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" بدهی):
- بیمه و مبلغ ویزیت: select بیمهی پایه + select بیمهی مکمل + قیمت ویزیت + تخفیف/سهم
- خدمات: انتخاب بخش/سرویس + chipهای انتخابشده (الگوی فعلی، فقط منظمتر)
- پرداخت و یادداشت: روش پرداخت + یادداشت
- خلاصه: آزاد / با بیمه پایه / با بیمه مکمل / جمع خدمات / مبلغ نهایی
۲. اتصال بیمه به قیمتگذاری پروفایل
- بیمههای 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 در پاسخ کم باشد).