feat: redesign appointments (نوبتها) admin UI to match tauri turns + expandable sidebar
Rebuild the /admin/appointments page visual layer to match the tauri
clinic-pro-tauri "turns" design while keeping all existing data wiring and
backend endpoints unchanged (add/edit/move/transfer-reserve/replace already
supported via PATCH /api/v1/appointment/{uuid} and POST /api/v1/my/appointment).
Frontend (assets/admin):
- Sidebar: نوبتها becomes an expandable parent with sub-items
«نوبت های تایید شده» (/admin/appointments) and «افزودن نوبت»
(/admin/appointments/new); auto-expands on active child. Applied to
admin/clinic/doctor/secretary roles. Adds nav-subitem styling.
- New presentational components under components/appointments/: tauri status
palette (turnStatus), TurnsStatInfo, TurnsViewToggle (sliding), DoctorTabs
(underline), TurnsTimeline (marker rail + status cards, empty slot → افزودن
نوبت), TurnsTable.
- AppointmentsPage recomposed with the new components (stats bar, doctor tabs,
view toggle, timeline/table), preserving queries, filters, pagination,
quick-book modal and the row actions menu.
- AppointmentCreatePage: full-page create form (CreateTurn layout) at
/admin/appointments/new, reusing POST /api/v1/my|admin/appointment.
Tests: TurnsStatInfo, TurnsTimeline, Sidebar (expandable), AppointmentsPage,
AppointmentCreatePage. Backend move/reserve/replace verified green via existing
tests/Appointment/AppointmentUpdateTest + AppointmentWorkflowFieldsTest.
No API endpoints changed → no docs/api change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* پیکربندی وضعیت نوبتها — رنگها عیناً از طرح tauri (`clinic-pro-tauri`
|
||||
* `src/components/turns/Timeline.jsx` → `statusConfig`) برداشته شده و به وضعیتهای
|
||||
* واقعی بکاند (Appointment::STATUS_*) نگاشت شدهاند. لیبلها فارسی مطابق همان طرح.
|
||||
*/
|
||||
export interface TurnStatusConfig {
|
||||
label: string;
|
||||
bgColor: string;
|
||||
darkBgColor: string;
|
||||
borderColor: string;
|
||||
darkBorderColor: string;
|
||||
dotColor: string;
|
||||
textColor: string;
|
||||
darkTextColor: string;
|
||||
}
|
||||
|
||||
// وضعیتهای بکاند → رنگ طرح tauri.
|
||||
const STATUS: Record<string, TurnStatusConfig> = {
|
||||
// pending = «ثبت شده» (tauri: registered)
|
||||
pending: {
|
||||
label: 'ثبت شده',
|
||||
bgColor: '#E3F2FD', darkBgColor: 'rgba(85, 89, 206, 0.18)',
|
||||
borderColor: '#2196F3', darkBorderColor: 'rgba(199, 206, 244, 0.42)',
|
||||
dotColor: '#2196F3', textColor: '#2196F3', darkTextColor: '#C7CEF4',
|
||||
},
|
||||
// confirmed = «قطعی شده» (tauri: finalized)
|
||||
confirmed: {
|
||||
label: 'قطعی شده',
|
||||
bgColor: '#E0F2F1', darkBgColor: 'rgba(25, 191, 211, 0.14)',
|
||||
borderColor: '#009688', darkBorderColor: 'rgba(25, 191, 211, 0.44)',
|
||||
dotColor: '#009688', textColor: '#009688', darkTextColor: '#19BFD3',
|
||||
},
|
||||
// following_up = «در حال پیگیری» (tauri: in_progress)
|
||||
following_up: {
|
||||
label: 'در حال پیگیری',
|
||||
bgColor: '#FFF3E0', darkBgColor: 'rgba(241, 119, 50, 0.16)',
|
||||
borderColor: '#FF9800', darkBorderColor: 'rgba(241, 119, 50, 0.46)',
|
||||
dotColor: '#FF9800', textColor: '#d87f00', darkTextColor: '#F17732',
|
||||
},
|
||||
// salon = «سالن»
|
||||
salon: {
|
||||
label: 'سالن',
|
||||
bgColor: '#F3E5F5', darkBgColor: 'rgba(199, 206, 244, 0.16)',
|
||||
borderColor: '#9C27B0', darkBorderColor: 'rgba(199, 206, 244, 0.42)',
|
||||
dotColor: '#9C27B0', textColor: '#9C27B0', darkTextColor: '#C7CEF4',
|
||||
},
|
||||
// completed = «ویزیت شده» (tauri: success)
|
||||
completed: {
|
||||
label: 'ویزیت شده',
|
||||
bgColor: '#E8F5E9', darkBgColor: 'rgba(34, 197, 94, 0.14)',
|
||||
borderColor: '#4CAF50', darkBorderColor: 'rgba(34, 197, 94, 0.42)',
|
||||
dotColor: '#4CAF50', textColor: '#0d9f43', darkTextColor: '#4ADE80',
|
||||
},
|
||||
// cancel variants = «لغو شده» (tauri: failed)
|
||||
cancelled_by_doctor: {
|
||||
label: 'لغو شده',
|
||||
bgColor: '#fde7e9', darkBgColor: 'rgba(255, 84, 80, 0.16)',
|
||||
borderColor: '#ee5c6d', darkBorderColor: 'rgba(255, 84, 80, 0.44)',
|
||||
dotColor: '#ee5c6d', textColor: '#ee5c6d', darkTextColor: '#FF7A76',
|
||||
},
|
||||
cancelled_by_user: {
|
||||
label: 'لغو توسط بیمار',
|
||||
bgColor: '#fde7e9', darkBgColor: 'rgba(255, 84, 80, 0.16)',
|
||||
borderColor: '#ee5c6d', darkBorderColor: 'rgba(255, 84, 80, 0.44)',
|
||||
dotColor: '#ee5c6d', textColor: '#ee5c6d', darkTextColor: '#FF7A76',
|
||||
},
|
||||
// no_show / expired = خنثی (tauri: pending amber-ish → اینجا خاکستری)
|
||||
no_show: {
|
||||
label: 'غیبت',
|
||||
bgColor: '#f4f4f5', darkBgColor: 'rgba(160, 160, 160, 0.14)',
|
||||
borderColor: '#9E9E9E', darkBorderColor: 'rgba(160, 160, 160, 0.4)',
|
||||
dotColor: '#9E9E9E', textColor: '#757575', darkTextColor: '#A1A1A1',
|
||||
},
|
||||
expired: {
|
||||
label: 'منقضی',
|
||||
bgColor: '#f4f4f5', darkBgColor: 'rgba(160, 160, 160, 0.14)',
|
||||
borderColor: '#9E9E9E', darkBorderColor: 'rgba(160, 160, 160, 0.4)',
|
||||
dotColor: '#9E9E9E', textColor: '#757575', darkTextColor: '#A1A1A1',
|
||||
},
|
||||
};
|
||||
|
||||
// اسلات خالی (نوبت جدید) — tauri: empty.
|
||||
export const EMPTY_SLOT_CONFIG: TurnStatusConfig = {
|
||||
label: 'نوبت جدید',
|
||||
bgColor: '#E3F2FD', darkBgColor: 'rgba(85, 89, 206, 0.16)',
|
||||
borderColor: '#2196F3', darkBorderColor: 'rgba(199, 206, 244, 0.38)',
|
||||
dotColor: '#2196F3', textColor: '#5559ce', darkTextColor: '#C7CEF4',
|
||||
};
|
||||
|
||||
export function turnStatusConfig(status: string): TurnStatusConfig {
|
||||
return STATUS[status] ?? EMPTY_SLOT_CONFIG;
|
||||
}
|
||||
|
||||
/** وضعیتهایی که نوبت را «لغوشده» میکنند (برای منطق تایملاین/آمار). */
|
||||
export const CANCELLED_STATUSES = new Set([
|
||||
'cancelled_by_doctor', 'cancelled_by_user', 'cancelled_by_admin',
|
||||
'auto_cancel_unpaid', 'no_show', 'expired',
|
||||
]);
|
||||
Reference in New Issue
Block a user