Admin-side booking (POST /api/v1/my/appointment and
/api/v1/admin/appointment) resolved the patient User by mobile only, so
one person booked under two mobiles produced two User rows — and two
case-files, since PatientRecord is keyed on user_id. National code is the
real unique identity (User.national_code is already unique); a person may
have several mobiles.
Booking now requires + validates patient_national_code and resolves the
patient national-code-first (then mobile) via a shared PatientResolver, so
the case-file stays unique per national code even across mobiles. Reusing a
mobile already bound to a different national code returns 422
ERR_PROFILE_MOBILE_TAKEN. The admin create form and NewAppointmentDrawer
gain a national-code field and send it; both had a dead patient-picker URL
(/api/v1/patient) fixed to the real /api/v1/patients, whose payload already
carries user_national_code for autofill.
Docs (appointment.md, admin.md) and tests updated; new
AppointmentNationalCodeTest covers success, single-file reuse, missing,
invalid, and identity-conflict cases.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebuild admin Topbar to match clinic-pro-tauri header:
- Icon order: theme -> settings -> bell (was theme -> bell -> settings)
- Settings gear now navigates to the role-based settings page
instead of opening the personalization panel
- Search placeholder changed to «جستجو», dropped the ⌘K hint
- Add ProfileMenu: avatar + user name + context/role subtitle + caret,
with a dropdown (profile / payments / settings / personalization / logout).
Links are role-aware; personalization keeps the existing settings panel.
Frontend-only, no API changes. Adds ProfileMenu.test + Topbar.test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Revert the earlier mis-scoped orange on the personalization panel and
instead expose rgb(241,119,50) as a selectable 'رنگ اصلی' swatch. When
picked it overrides --primary/-600/-700/-soft/-soft2/-ring inline with
exact hex, so every var(--primary) consumer across the whole admin
(buttons, active nav, rings) becomes that orange. Non-fixed hues keep
the oklch hue pipeline (inline overrides removed on switch).
- uiStore: BrandHue interface + optional fixed hex; shared applyBrand()
helper handles fixed vs hue, dark-aware soft tints
- AdminLayout: reuse applyBrand() (no divergence with store)
- Topbar: swatch shows the exact fixed color
- tests: fixed-color apply, dark soft, and override-cleanup on switch
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apply rgb(241,119,50) exclusively to the personalization (شخصیسازی)
settings panel — its heading and active segmented buttons — matching
the product requirement that this section use the dedicated orange
while the rest of the panel keeps tauri's purple.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the admin panel's visual system to the tauri source app:
- neutralize color tokens (border/surface-2/3, text 1-3) from the
bluish indigo tint to tauri's neutral grays (#efefef/#3b3b3b/#7e7e7e/#a1a1a1)
- add --nav-active-bg (#f8f8ff light) for the sidebar active item,
matching tauri active-link-side
- enable Vazirmatn ss02 stylistic set on body (tauri typography)
- responsive topbar heights 56/67/79/90 exactly as tauri
Settings sub-sidebar active orange (#f17732 = rgb(241,119,50)) and
ClinicPro branding/section grouping kept per product decision.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AppointmentDetailPage now derives the appointment's local day from slot_start
and points both the «بازگشت» button and the «نوبتها» breadcrumb to
/admin/appointments?date=<that day>, so viewing/acting on an appointment from
any day returns to that day instead of today.
Test: the «نوبتها» breadcrumb links back to the appointment's date.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AppointmentsPage now reads an optional ?date=YYYY-MM-DD query param as its
initial selected date. AppointmentEditPage and AppointmentCreatePage navigate
back to /admin/appointments?date=<the appointment's day> on save (and the edit
page's back link carries the date too), so the user returns to the day they
were viewing instead of today.
Test: AppointmentsPage honors ?date= and fetches that day.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Multi-doctor clinic profile (clinic/admin) shows the doctor tabs for
multi-doctor management; clinic auto-selects the first doctor so the timeline
loads immediately (as in the reference). Admin keeps the «همه» tab.
- Independent doctor profile (doctor role, incl. clinic-scoped guest) shows no
tabs and only its own schedule — no clinic/doctor selection.
- Toolbar reordered to match the reference: date + service select
(«سرویس مورد نظر را انتخاب کنید...») + view toggle on the right; filter +
«افزودن نوبت» on the left. The in-toolbar doctor picker is removed (doctor
selection is via tabs); the personnel select is replaced by a service filter
bound to the existing itemUuid filter (client-side, no new endpoint).
Tests: added clinic-profile tests (tabs shown, no «همه», first doctor
auto-selected) and independent-doctor test (no tabs, service filter shown).
No API endpoints changed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Center the whole page in a max-width container; move the toolbar above the
card and make the doctor tabs the card header (as in the tauri turns design).
- Rebuild the timeline card to match the reference: inner start/end ring-dot
time markers, patient name / phone / «سرویس» lines, and status pill + عملیات
on the card's left; outer marker rail with time on the right.
- Timeline rows are width-capped and centered on the page.
- Empty slots render the light-blue «افزودن نوبت +» card with a «نوبت جدید» pill.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
- Added a new 'category' field to the InventoryItem entity and updated the database schema.
- Replaced free-text input for 'unit' and 'category' with select dropdowns in the AddItemModal.
- Introduced a new API endpoint to fetch metadata for units and categories.
- Updated inventory filtering logic to use the new 'category' field instead of 'consumable'.
- Enhanced validation for item creation and updates to ensure valid unit and category values.
- Updated tests to cover new functionality and ensure proper validation.
Show the قیمت (تومان) field with thousand separators as the user types
(e.g. 1200000 → 1,200,000). Stored value stays digit-only, so the
Toman→Rial conversion on submit is unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The «عملیات» dropdown was absolutely positioned inside the table container,
which has overflow:hidden for its rounded corners, so the menu was clipped
below the table. Render it through a Portal with fixed positioning computed
from the trigger's rect (RTL-aligned to the trigger's right edge), tracking
scroll/resize while open.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a per-tenant (doctor/clinic) Inventory domain and admin page, ported
from clinic-pro-tauri /inventory (which was static/mock) into a real feature.
Backend (src/Inventory/):
- Entities InventoryItem, InventoryPackage, InventoryPackageItem, scoped via
entity_type/entity_id like TenantTag. Item status is derived, package total
and availability derived at read time.
- InventoryService (stats, package assembly, availability), thin
InventoryController with CRUD for items and packages + categories endpoint.
- Migration + docs/api/inventory.md + functional tests (10 tests, 42 assertions).
Frontend (assets/admin/):
- InventoryPage with two tabs (کالاهای مصرفی / پکیج), stat cards, items table
(desktop + mobile cards), packages accordion, add/edit item and package
modals, search + category filter — pixel-matched to the tauri source.
- useInventory hook (TanStack Query), route + sidebar link for doctor/clinic.
- Vitest coverage (real data, empty state, modal, packages tab).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Created a new JSON file containing nodes and edges representing the structure of the insurance API documentation.
- The nodes include various API endpoints, their labels, file types, and source locations.
- The edges define relationships between the nodes, indicating how they are connected within the documentation.
Rebuild the /admin/insurance-pricing contracts UI to the Figma "مدیریت بیمه"
design and inject the coverage/franchise/ceiling fields the design omitted.
Backend:
- Add contract-level `kind` column to TenantInsurance (basic|supplementary),
defaulting to the catalog type; migration Version20260715093358.
- POST/PATCH /billing/tenant-insurances now accept effective_from,
effective_to, kind; PATCH also toggles is_active without clobbering the
user-set effective_to (unlike DELETE/deactivate).
- List returns the latest version of every insurance (active + inactive) via
TenantInsuranceRepository::findLatestByTenant, for the فعال/غیرفعال toggle.
Frontend:
- New InsuranceModal (ui/Modal + SearchableSelect + PersianDateInput) with the
seven fields; submit "ثبت بیمه".
- TenantInsuranceContracts rebuilt: header + search box, desktop table
(ردیف/نام/کد/نوع/وضعیت/عملیات) and mobile cards, status toggle -> PATCH.
- utils: isoToUnix/unixToIso helpers for contract dates.
Tests: TenantInsuranceContractApiTest (create/edit/toggle/list, 5 cases),
InsuranceModal + TenantInsuranceContracts vitest suites, docs/api updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The custom inline overlay was mounted inside the SettingsLayout grid, so the
fixed positioning resolved against a transformed ancestor and the modal
rendered top-aligned and full-width. Use the shared Modal (portal to body)
for a correctly centered card; keep the tauri-styled form body + permission
accordions as its children.
Remove پرسنل (/admin/staff) and منشی ها (/admin/my-secretaries) from the
clinic and doctor main sidebars; surface them under the settings menu instead
(PurchaseSubscriptionSidebar + SETTINGS_MENU). Wrap StaffPage in SettingsLayout
so it renders inside the settings shell like MySecretariesPage already does.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add per-clinic payment methods (bank accounts + POS/card-reader devices)
under the "مدیریت پرداخت" settings tab at /admin/my-financial, ported from
clinic-pro-tauri's mock-only PaymentManagement tab into a real persisted
feature. These records are referenceable (by uuid) from patient invoices to
record which method a service payment was made with.
Backend (new src/PaymentMethod domain):
- BankAccount + Pos entities, repositories, PaymentMethodService (validation,
ownership scoping, create/update/toggle logic).
- Thin PaymentMethodController exposing /api/v1/my/payment-methods/{bank-accounts,pos}
(GET/POST/PUT + PATCH .../status), guarded to clinic/doctor/secretary/admin.
- Migration for bank_accounts + pos_devices tables.
- Functional tests (success + validation/404/403 + empty boundaries).
- docs/api/payment-method.md.
Frontend:
- Replace MyFinancialPage content with the payment-management UI (two tabs,
tables, add/edit modals, status toggle) using the admin design system.
- usePaymentMethods hook (TanStack Query) + presentational components.
- Update page test to cover tabs, data, empty state and the add modal.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Removed the maxWidth:1060 centered wrapper on PatientDetailPage that
boxed the page; tauri's FilesServices renders full-width in a plain Box.
Added a regression test asserting the root wrapper has no max-width cap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rebuild the پروندهها header to mirror tauri files/head + files/inputs:
- title on its own row (font-bold, #525252, 16/18/20px).
- search field: 48px tall, #FAFAFA bg, #EFEFEF border, rounded-[6px], with a
#5559CE 40px search-icon box (SearchHeaderP).
- view toggle with the exact tauri SVGs (PatientsGridView table / Patients
CategoryView card), active bg #f4f5fd, #E0E0E0 border.
- filter button as a 62x48 #5559ce-bordered box (TurnsFilter icon).
- تشکیل پرونده as a 48h/137w #5559ce button (AddTurn icon + label).
Ported icons verbatim into components/icons/FilesToolbarIcons.tsx.
Frontend only. Tests + tsc + build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- default view is now the card grid (was table), matching tauri /files
(viewMode='card').
- rebuild the patient card to mirror tauri files/list/CardView exactly:
avatar-in-circle + name + ⋮ actions menu (view/edit) header, شماره پرونده /
موبایل rows, برچسبها footer with the inline tag popover. Same Tailwind
classes/colors/spacing (rounded-[6px], #EDEDED/#E0E0E0 borders,
grid md:grid-cols-4 gap-[12px]).
- per-view page size like tauri: 16 for card, 12 for table; reset page on
view switch.
- empty state text 'بیماری یافت نشد'.
Frontend only; no API change. Tests updated (default card, ⋮ menu, table
toggle, tag popover, filter apply) — all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Port the remaining pieces of tauri /files list into /admin/patients:
- inline tag assignment: the برچسبها cell (table + card) opens a popover to
assign/remove tenant tags without leaving the list. Uses existing endpoints
(GET /api/v1/tenant-tags + PATCH /api/v1/patient/{uuid} { tags:[uuid] }).
New component assets/admin/components/PatientTagsCell.tsx.
- advanced filter modal (PatientsFilterModal): admission date range, insurance,
service status (pending/completed), has-debt, gender, tags — wired to the
list query with an active-filter badge on the button.
Backend: GET /api/v1/patients gains tags/gender/insurance_id/admitted_from/
admitted_to/service_status/has_debt filters via a shared applyFilters() on
PatientRecordRepository (findByEntity + countByEntity stay consistent). Debt
and service status derive from unpaid sessions (payment_method='pending'),
documented in docs/api/patient.md.
Tests: tests/Patient/PatientListFilterTest.php (5) + PatientsListPage tag-popover
and filter-apply tests. Pre-existing LoginPage.test failures are unrelated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>