# بازطراحی UI/UX پنج صفحه کلینیک‌پرو ## زمینه پروژه ClinicPro یک پنل مدیریت کلینیک است با React 19 + TypeScript و یک سیستم CSS دیزاین اختصاصی. SubscriptionPage اخیراً بازطراحی شده و الگویی ایجاد کرده که بقیه صفحات باید با آن هم‌راستا شوند. ۵ صفحه هنوز از ساختار قدیمی استفاده می‌کنند: جدول‌های ساده، کارت‌های بدون سلسله‌مراتب بصری، و فرم‌های بدون هویت. هدف این است که هر صفحه را به یک تجربه منسجم، مدرن و RTL-first تبدیل کنیم. ## سیستم CSS موجود متغیرها و کلاس‌های قابل استفاده (در `assets/admin/styles.css`): ```css /* متغیرها */ --primary: oklch(0.55 0.2 256) --primary-subtle: oklch(0.97 0.02 256) --surface: #fff --border: oklch(0.9 0 0) --text-1 / --text-2 / --text-3 --r (border-radius base) --gap / --card-pad /* کلاس‌های کاربردی */ .card /* white surface با shadow و border-radius */ .card-pad /* padding داخل card */ .stat /* عدد آماری بزرگ + label */ .stat-grid /* grid چند ستونه برای stat‌ها */ .badge green/red/yellow/blue/gray /* برچسب وضعیت */ .btn primary/sm/ghost /* دکمه */ .field /* label + input wrapper */ .seg /* segment/tab selector */ .bar /* نوار پیشرفت */ .grid-2 /* دو‌ستونه responsive */ .avatar sm /* آواتار دایره‌ای */; ``` **الگوی header صفحات:** `} />` ## فایل‌های مرتبط | فایل | نقش | | ------------------------------------------- | -------------------------------------------------------- | | `assets/admin/pages/MyPatientsPage.tsx` | پرونده بیماران — دو حالت: لیست + جزئیات بیمار | | `assets/admin/pages/StaffPage.tsx` | مدیریت پرسنل — CRUD | | `assets/admin/pages/MySecretariesPage.tsx` | مدیریت منشی ها — CRUD + permissions matrix | | `assets/admin/pages/ClinicServicesPage.tsx` | سرویس‌های کلینیک — دو پنل: بخش‌ها + آیتم‌ها | | `assets/admin/pages/SmsWalletPage.tsx` | کیف پول پیامک — balance + settings + logs | | `assets/admin/styles.css` | سیستم CSS کامل | | `assets/admin/pages/SubscriptionPage.tsx` | **مرجع طراحی** — بازطراحی‌شده با gradient + progress bar | ## وضعیت فعلی هر صفحه ### ۱. MyPatientsPage دو حالت: حالت لیست و حالت پرونده بیمار. **حالت لیست:** یک `.card` با `` ساده + search input بدون styling در header. **حالت پرونده بیمار:** `PageHeader` با نام + برگشت. یک `.card` با `sessions.map(SessionRow)`. Modal ثبت مراجعه با سه‌ستونه برای قیمت/بیمه/روش پرداخت. ```tsx // لیست ساده فعلی
``` **ستون‌های لیست بیماران:** آواتار + نام + تلفن، تاریخ ثبت، دکمه «پرونده». **SessionRow:** هنوز خوانده نشده — احتمالاً نمایش تجمیعی اطلاعات مراجعه. ### ۲. StaffPage ```tsx // فعلی — جدول + دو modal افزودن پرسنل} />
// Modal ایجاد و ویرایش با StaffFormFields (فیلدهای: full_name, phone, job_title, address, national_code) ``` ستون‌ها: نام، سمت، تلفن، کد ملی، وضعیت (ActiveBadge)، تاریخ ثبت، عملیات. هیچ KPI یا آمار مقدماتی ندارد. ### ۳. MySecretariesPage ```tsx // جدول دستی (نه DataTable) ... {secretaries.map((s, i) => ( ... ))}
نام
{s.user_name}
``` PermissionsMatrix: جدول checkbox با ۶ ستون برای ۴ بخش — داده‌محور و قابل استفاده اما بصری ضعیف. حالت Empty state: فقط یک div با متن `هنوز منشی‌ای ثبت نشده است`. ### ۴. ClinicServicesPage ```tsx // دو پنل side-by-side
{/* پنل بخش‌ها */}
بخش‌ها
{sections.map((s) => (
...
))}
{/* پنل آیتم‌ها */}
...
``` مشکل: بخش‌ها فقط text + دو آیکون هستند. active/inactive badge ندارند. جدول آیتم‌ها خیلی ساده است. ### ۵. SmsWalletPage ```tsx // دو کارت بالا
{/* موجودی */}
موجودی کیف پول
{formatRial(balance?.balance_rials ?? 0)}
معادل {formatNumber(...)} پیامک
{/* تنظیمات */}
...
{/* جدول تراکنش‌ها */}
...
``` کارت موجودی: عدد بزرگ اما بدون visual hierarchy. نوار پیشرفت و badge «موجودی» ندارد. ## وظایف ### ۱. بازطراحی MyPatientsPage **هدف:** لیست با identity واضح + پرونده بیمار با مینی‌داشبورد. **الف — حالت لیست بیماران:** - Header اختصاصی: `` با description «مراجعه‌کنندگان ثبت‌شده شما» - Search bar را با یک wrapper card جداگانه به یک toolbar تبدیل کن (نه داخل card جدول) - `DataTable` را با ردیف‌های بهتر جایگزین کن: هر ردیف آواتار gradient + نام بولد + شماره با آیکون تلفن + تاریخ ثبت شمسی - دکمه «پرونده» به آیکون `FolderOpenIcon` + متن «مشاهده پرونده» تبدیل شود (btn primary sm) - وقتی بیماری نیست: Empty State با آیکون بزرگ + متن راهنما **ب — حالت پرونده بیمار (selectedRecord):** - PageHeader با نام بیمار + شماره + تاریخ ثبت - یک بنر/info-card بالای صفحه: نام، تلفن، تعداد مراجعات (از `totalSes`) - SessionRow باید بهتر شود — هر مراجعه یک card مستقل با: - سربرگ: تاریخ شمسی + روش پرداخت به عنوان badge - بدنه: قیمت ویزیت + تخفیف بیمه + جمع خدمات + قیمت نهایی در یک `.grid-2` یا flex row - footer: لیست خدمات (services) اگر وجود داشت - دکمه «ویرایش» در گوشه بالا سمت چپ کارت **ج — Modal ثبت مراجعه:** - سه فیلد قیمت/بیمه پایه/بیمه تکمیلی را در یک `.grid-2` یا grid سه‌ستونه گذاشتن خوب است — این کافیست - بخش «خدمات» را با یک separator بصری از فیلدهای اصلی جدا کن - لیست خدمات انتخاب‌شده را با badge یا chip نشان بده (نه فقط متن) **نکته:** SessionRow را کامل بخوان قبل از پیاده‌سازی. --- ### ۲. بازطراحی StaffPage **هدف:** صفحه‌ای با KPI bar + جدول بهتر + فرم واضح‌تر. **الف — KPI bar:** - بالای جدول، یک `.stat-grid` با ۳ card: تعداد پرسنل کل، تعداد فعال، تعداد غیرفعال - داده از همان `staff` query محاسبه شود (نه API جدید): ```ts const total = staff.length; const active = staff.filter((s) => s.active).length; const inactive = total - active; ``` **ب — جدول بهتر:** - ستون «نام» را بهبود بده: `full_name` + `job_title` زیرش (مثل MyPatientsPage) - ستون «تلفن» و «کد ملی» را در موبایل پنهان کن (CSS media query اگر لازم بود) - ردیف‌های hover state با background تغییر کند **ج — فرم StaffFormFields:** - فیلدهای `full_name` و `job_title` را در یک ردیف (`.grid-2`) قرار بده - فیلدهای `phone` و `national_code` را در یک ردیف دیگر - فیلد `address` تنها بماند (textarea یا input تمام عرض) --- ### ۳. بازطراحی MySecretariesPage **هدف:** جدول دستی را به DataTable شیک تبدیل کن + PermissionsMatrix بصری‌تر + Empty State جذاب. **الف — جدول منشی ها:** - جدول دستی را **حذف کن** و از `DataTable` component استفاده کن - ستون «نام»: آواتار کوچک (initial از `user_name`) + نام بولد - ستون «موبایل»: با `maskMobile()` و `dir="ltr"` + آیکون تلفن - ستون «وضعیت»: `` - ستون «تاریخ»: `formatDate()` - ستون «عملیات»: دو دکمه `sm` (ویرایش دسترسی‌ها + غیرفعال‌سازی) **ب — Empty State:** - وقتی `secretaries.length === 0`: ```tsx
هنوز منشی‌ای اضافه نشده
منشی می‌تواند نوبت‌ها و اطلاعات کلینیک را مدیریت کند
``` **ج — PermissionsMatrix:** - ردیف‌های جدول با رنگ متناوب (striped) یا hover state - checkbox‌ها با `accent-color: var(--primary)` (قبلاً بود، نگه دار) - header ستون‌ها را bold و با background کم‌رنگ کن - برای cell‌های `—` (N/A) رنگ `var(--border)` خوب است --- ### ۴. بازطراحی ClinicServicesPage **هدف:** پنل بخش‌ها بهتر + جدول آیتم‌ها با badge فعال/غیرفعال. **الف — پنل بخش‌ها (ستون ۲۸۰px):** - هر بخش یک item با: - آیکون `WrenchScrewdriverIcon` در سمت راست (color از theme) - نام بخش bold - badge «فعال» / «غیرفعال» بر اساس `s.active` - دکمه‌های edit/delete فقط هنگام hover نشان داده شوند (opacity transition) - انتخاب شده: border `var(--primary)` + background `var(--primary-subtle)` - افزودن بخش: دکمه با آیکون + متن «بخش جدید» (نه فقط آیکون) **ب — پنل آیتم‌ها (ستون 1fr):** - بالای جدول یک toolbar: نام بخش به عنوان breadcrumb + تعداد آیتم‌ها + دکمه «سرویس جدید» - هر row آیتم: - badge «فعال» / «غیرفعال» برای `item.active` - قیمت با `formatRial()` و رنگ primary - نام پرسنل با avatar خیلی کوچک اگر وجود داشت - Empty state وقتی `items.length === 0`: ```tsx
سرویسی در این بخش وجود ندارد
``` **ج — State اولیه (هیچ بخشی انتخاب نشده):** - جای پیام «یک بخش را از سمت راست انتخاب کنید» یک آنیمیشن ساده یا placeholder card با رنگ dashed border قرار بده: ```tsx
یک بخش انتخاب کنید تا سرویس‌های آن را ببینید
``` --- ### ۵. بازطراحی SmsWalletPage **هدف:** کارت موجودی با visual hierarchy قوی + تنظیمات واضح‌تر + جدول تراکنش‌ها با visual type indicator. **الف — کارت موجودی:** - gradient background (مثل SubscriptionPage): `background: linear-gradient(135deg, oklch(0.52 0.22 256), oklch(0.40 0.18 256))` - رنگ متن: white - موجودی را بزرگ‌تر کن: `fontSize: 36, fontWeight: 800` - زیر موجودی: نوار پیشرفت `.bar` که نشان می‌دهد چند پیامک باقی‌مانده (نسبت به یک سقف فرضی مثلاً ۵۰۰ پیامک یا بر اساس estimated_sms_count) - badge status: اگر `estimated_sms_count < 10` → badge قرمز «موجودی کم»، اگر ≥ 10 → badge سبز «فعال» - دکمه شارژ: white با primary text (برعکس از theme معمول) **ب — کارت تنظیمات:** - عنوان با divider پایین - هر toggle را با یک card داخلی wrapper کن: ```tsx
یادآوری قبل از نوبت
ارسال خودکار چند ساعت قبل از نوبت
``` - input «چند ساعت قبل» را با border و padding واضح‌تر style کن **ج — جدول تراکنش‌ها:** - ستون «نوع» را با یک آیکون بهبود بده: - `credit`: `ArrowUpCircleIcon` با رنگ سبز - `debit`: `ArrowDownCircleIcon` با رنگ قرمز - ستون «مبلغ» را بر اساس نوع رنگ بده: credit → سبز، debit → قرمز - header table با background خاکستری کم‌رنگ **د — Modal شارژ:** - انتخاب gateway را به radio card تبدیل کن (مثل SubscriptionPage): ```tsx { (["mellat", "sep"] as const).map((gw) => (
setGateway(gw)} style={{ border: `2px solid ${gateway === gw ? "var(--primary)" : "var(--border)"}`, borderRadius: 8, padding: "10px 14px", cursor: "pointer", background: gateway === gw ? "var(--primary-subtle)" : "", transition: "all 0.15s", flex: 1, textAlign: "center", }} >
{gw === "mellat" ? "بانک ملت" : "سپ"}
)); } ``` - پیش‌نمایش مبلغ: وقتی کاربر عدد می‌زند، زیر input بنویس «پرداخت X ریال از طریق Y» ## نکات مهم 1. **فقط فرانت‌اند** — هیچ endpoint، migration، یا تغییر backend لازم نیست 2. **CSS موجود را استفاده کن** — هیچ کتابخانه جدید اضافه نکن. inline style برای تنظیمات جزئی قابل قبول است 3. **DataTable component موجود** در `assets/admin/components/ui/DataTable.tsx` — برای جداول از آن استفاده کن (ترجیحاً بر inline table) 4. **RTL** رعایت شود — padding/margin/icon placement همه RTL-first باشد 5. **هر صفحه مستقل** پیاده‌سازی شود — نه refactor مشترک 6. **SubscriptionPage** را به عنوان مرجع visual نگه دار — gradient، progress bar، و card layout آن مدل است 7. **بعد از هر صفحه** `ddev exec yarn dev` اجرا کن تا TypeScript error نداشته باشد 8. **SessionRow** در MyPatientsPage: قبل از ویرایش، آن component را کامل بخوان (احتمالاً inline در همان فایل است) 9. **`maskMobile()`** از `../lib/utils` — برای نمایش شماره موبایل منشی ها استفاده کن 10. **`formatDate()` و `formatDateTime()`** — همه تاریخ‌ها شمسی نمایش داده شوند