Commit Graph
246 Commits
Author SHA1 Message Date
hamedandClaude Opus 4.8 170cd5f37e style: restyle appointment create page to match tauri CreateTurn mockup
Widen card to 1080px, 18px section headings, multi-column grids
(patient 3-col, service 3-col, slot-mode time 4-col), search field +
outlined 'new patient' button row, toggle switch for deposit, orange
wallet charge button, right-aligned submit. Service/slot booking logic,
endpoints, validation, and placeholders unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 09:18:29 +03:30
hamed b1b99903ec Replace all native <select> elements in the admin panel with SearchableSelect for a consistent UI experience. This change enhances accessibility, supports RTL and dark mode, and improves the overall design by utilizing a common component. The updates include adjustments to state management and event handling to ensure seamless integration with existing functionality across various pages and components. 2026-07-16 08:56:59 +03:30
hamed 7b8a5c2775 feat(date-input): refactor PersianDateInput to use PersianDatePicker for Jalali calendar support 2026-07-16 08:26:39 +03:30
hamed 2f060bd5be feat(timezone): implement Tehran timezone handling across the application 2026-07-16 00:25:21 +03:30
hamed 8cd1253b81 feat(appointment): enhance service mode to display available booking slots between appointments 2026-07-16 00:16:37 +03:30
hamed 4715649fd8 feat(appointment): implement service mode functionality with service slot selection and validation 2026-07-16 00:02:36 +03:30
hamed 2df16c6d29 feat(appointment): implement immutable booking mode after first save and update API documentation 2026-07-15 23:33:00 +03:30
hamed 5937f7e176 feat: add service-based booking mode to appointment scheduling
- Introduced a new booking mode in WeeklySchedule to support service-based appointments.
- Updated SlotCalculatorService to calculate available start times based on selected service durations and buffer times.
- Enhanced AppointmentController to handle service items during booking, calculating slot_end on the server side.
- Implemented validation to ensure at least one bookable service exists for doctors in service mode.
- Added new API endpoint to retrieve available appointment slots based on selected services.
- Updated MyAppointmentsController to accept service items during appointment creation.
- Modified ServiceItem entity to include a bookable flag, allowing services to be marked for scheduling.
- Created migration to add bookable column to service_items table.
- Added tests for service-based slot calculations and validation logic.
2026-07-15 23:15:45 +03:30
hamed 0dc1ab949a feat(appointment): add Enter key functionality for mobile search in appointment modal 2026-07-15 18:29:59 +03:30
hamed 5d5089244b feat: add mobile-based patient lookup for appointment booking
- Implemented a new endpoint `/api/v1/my/appointment/patient-lookup` to search for patients by mobile number before booking an appointment.
- Updated the `NewAppointmentModal` component to utilize the new patient lookup feature, allowing for direct booking if the patient is found with a national code.
- Enhanced the appointment booking form to handle mobile input normalization and display relevant fields based on the search results.
- Added tests for the new patient lookup functionality, ensuring proper behavior for found and not found cases, as well as validation for mobile input.
- Updated sidebar tests to reflect changes in the sidebar component structure and functionality.
2026-07-15 18:27:29 +03:30
hamedandClaude Opus 4.8 5548d79d4c feat(appointment): identify admin-booked patient by national code
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>
2026-07-15 18:11:40 +03:30
hamed 952fcf3634 style: enhance SettingsLayout and AppointmentSettingsPage for improved layout and spacing 2026-07-15 17:35:24 +03:30
hamed ffc4351038 fix: update PurchaseSubscriptionSidebar and AppointmentSettingsPage for pixel-perfect alignment and color consistency 2026-07-15 17:30:26 +03:30
hamed 5c15a4dd7f feat(services): add services menu item to sidebar and update related components 2026-07-15 16:35:02 +03:30
hamedandClaude Opus 4.8 10d289cfd1 fix(appointments): detail page back/breadcrumb return to the appointment day
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>
2026-07-15 16:20:22 +03:30
hamedandClaude Opus 4.8 526048fd56 fix(appointments): stay on the same day after edit/create
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>
2026-07-15 16:13:32 +03:30
hamedandClaude Opus 4.8 f41852b168 feat(appointments): profile-aware doctor tabs + toolbar to match tauri turns
- 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>
2026-07-15 16:07:04 +03:30
hamedandClaude Opus 4.8 48c70e89f2 fix(appointments): center timeline card and match tauri turns layout
- 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>
2026-07-15 15:45:51 +03:30
hamedandClaude Opus 4.8 a6ae6220cb 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>
2026-07-15 15:33:03 +03:30
hamed 9f75aeedf5 feat: redesign insurance pricing page with tabbed navigation for basic and supplementary insurance, expandable rows for contract details, and move free visit price card to appointment settings 2026-07-15 14:55:16 +03:30
hamed 3e5dee0ad5 feat: Implement category and unit selection for inventory items
- 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.
2026-07-15 14:32:29 +03:30
hamedandClaude Opus 4.8 defa0db023 feat: group thousands in inventory item price input
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>
2026-07-15 14:09:49 +03:30
hamedandClaude Opus 4.8 519bc8d7f6 feat: port inventory (انبارداری) page from tauri to admin dashboard
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>
2026-07-15 13:48:29 +03:30
hamed e94f832c8a fix: adjust styles for PermissionAccordions component for better usability 2026-07-15 12:47:42 +03:30
hamed 28032892da fix: render secretary modal via portal Modal component (centered card)
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.
2026-07-15 12:28:18 +03:30
hamedandClaude Opus 4.8 89e23a2c0d feat: port secretaries tab from tauri to admin my-secretaries page
- Redesign MySecretariesPage pixel-perfect to clinic-pro-tauri (active/previous
  tabs, desktop table, mobile cards, add/edit/view modal with permission
  accordions, deactivate confirm)
- Permission sections based on existing admin pages (appointments, patients,
  payments, insurances, addresses, clinic_info)
- Extend DoctorSecretary with national_code + address columns (+migration);
  wire create/update in SecretaryController; add patients/payments to
  DEFAULT_PERMISSIONS
- Extend Secretary/SecretaryPermissions types; update admin SecretariesPage
- Backend + frontend tests; update docs/api/secretary.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 12:23:17 +03:30
hamedandClaude Opus 4.8 850b2832ff refactor: move secretary and staff management from main nav to settings menu
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>
2026-07-15 11:51:31 +03:30
hamedandClaude Opus 4.8 cf02fdd433 fix: add card padding on payment management page so content isn't flush to edges
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 11:44:00 +03:30
hamedandClaude Opus 4.8 b459d082a4 feat: port payment management tab from tauri to admin dashboard
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>
2026-07-15 11:39:32 +03:30
hamedandClaude Opus 4.8 f0b7a51b8f fix: make patient detail page full-width to match tauri FilesServices
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>
2026-07-15 11:16:40 +03:30
hamedandClaude Opus 4.8 be4d63744d feat(patients): port tauri /files-services detail pixel-for-pixel
Rebuild the patient case-file (/admin/patients/:uuid) to match tauri
files-services:
- breadcrumb (پرونده > name) + 140px patient banner (name + completion chip,
  file number, tag dots, phone/date rows, next appointment, یادداشت button)
  ported from BreadcrumbHeader + FileServicesHeader.
- services tab: replaced the plain list with the ServiceCard «مراجعه» grid —
  each card = a session (visit + performed services): success icon, services
  subtitle, doctor/date/notes rows, cost + remaining debt, تکمیل پرداخت
  (settles the session) / مشاهده فاکتور.
- مشاهده فاکتور opens InvoiceSummaryModal (خلاصه فاکتور tables) fed by the real
  invoice (GET /billing/invoices/{uuid}).
- tab bar now uses the tauri custom SVG icons.
- 20+ SVGs ported verbatim into components/icons/FilesServiceIcons.tsx; new
  components SessionServiceCard, PatientCaseBanner, InvoiceSummaryModal.

Frontend only — the sessions endpoint already returns invoice_uuid /
patient_debt_rials / is_paid. Tests updated (9 green).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 10:36:47 +03:30
hamedandClaude Opus 4.8 38ba3ee8ea style(patients): match tauri /files toolbar pixel-for-pixel
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>
2026-07-15 09:39:16 +03:30
hamedandClaude Opus 4.8 8697c94886 feat(patients): default to card view, match tauri /files CardView pixel-for-pixel
- 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>
2026-07-15 09:31:50 +03:30
hamedandClaude Opus 4.8 fd91840ba2 feat(patients): inline tag popover + advanced filters on the records list
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>
2026-07-14 19:40:54 +03:30
hamedandClaude Opus 4.8 818506bf36 refactor(billing): rebuild payments list as flat invoice list (tauri parity)
Align /admin/my-payments with the tauri /payments source (per user): the list
is now a flat, newest-first list of the tenant's recorded invoices — one row
per invoice — instead of the per-patient aggregation built from Figma.

Backend:
- replace InvoiceRepository::patientPaymentSummary aggregation with
  tenantInvoices/countTenantInvoices (flat, joins patient name/national code).
- InvoiceService::patientPaymentList → tenantInvoiceList.
- BillingController: GET /api/v1/my/billing/patient-payments →
  GET /api/v1/my/billing/payments returning
  { invoice_uuid, patient_uuid, patient_name, national_code, issued_at,
    amount_rials, status } rows.
- node-2 patient invoices endpoint unchanged.

Frontend:
- useMyPayments: usePatientPayments → usePayments (flat PaymentRow).
- MyPaymentsPage columns match tauri DetailT: row #, avatar+name, national
  code, date-time, amount paid, مشاهده (no status column); 'اضافه کردن بیمار'
  links to /admin/patients/new. Filters (national code / status / Jalali date
  range) kept.

Tests + docs/api/billing.md updated. Intentionally omitted tauri extras:
mobile Cards view and the advanced ModalFilter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 19:00:17 +03:30
hamedandClaude Opus 4.8 4c29fa3274 feat(billing): patient payments list + patient invoices detail (doctor/clinic)
Port two nobat724 Figma screens into the admin SPA for the doctor/clinic
tenant panel:

- node 1 — لیست پرداخت‌ها (/admin/my-payments): per-patient payment summary
  (invoice count, paid, remaining, derived status paid/unsettled/unpaid),
  filters by national code / status / Jalali date range, pagination.
- node 2 — پرداخت‌های ثبت‌شده (/admin/my-payments/:patientUuid): a patient's
  recorded invoices with patient header, service title, total, status badge,
  and an expandable per-invoice item breakdown.

Backend (App\Billing):
- InvoiceRepository::patientPaymentSummary/countPatientPaymentSummary — DQL
  aggregation grouped by patient record (arbitrary join Invoice→PatientRecord
  →User), draft/void excluded, derived-status HAVING filters.
- InvoiceRepository::invoicesForPatient/count + InvoiceService methods that
  shape rows and derive status.
- BillingController: GET /api/v1/my/billing/patient-payments and
  GET /api/v1/my/billing/patients/{patientUuid}/invoices (thin, resolveEntity,
  tenant-scoped, 403/404). Invoice::getIssuedAt / InvoiceItem::getTitle added.
- docs/api/billing.md documents both endpoints.

Frontend: useMyPayments hooks, MyPaymentsPage, MyPaymentDetailPage, routes in
App.tsx (doctor/secretary/clinic, blockClinicScope) and a sidebar entry.
Persian strings hardcoded per existing admin convention (no i18n infra).

Tests: tests/Billing/PatientPaymentsTest.php (8), useMyPayments + both page
tests (11). Note: pre-existing LoginPage.test failures are unrelated (proven
by stashing this change).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 18:24:33 +03:30
hamedandClaude Opus 4.8 2337cfd90c fix(services): restore separate insurance modal + fix ⋮ menu position
- revert the previous merge of insurance coverage into the service edit
  modal (per user): 'پوشش بیمه' is again a ⋮ menu action opening its own
  ServiceInsuranceModal, kept within the services page
- delete the inline ServiceInsuranceSection; restore ServiceInsuranceModal
- fix ⋮ dropdown position: left:8 → insetInlineStart:8 so the menu anchors
  under the ⋮ button (which sits at inline-start/right in RTL) instead of
  the opposite side
- keep the --primary-subtle → --primary-soft token fix in the modal
- test: assert the ⋮ menu exposes ویرایش / تعرفه‌های سالانه / پوشش بیمه

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 17:36:17 +03:30
hamedandClaude Opus 4.8 c79720ee79 refactor(services): merge insurance coverage into the service edit modal
- extract ContractCard + contracts list from ServiceInsuranceModal into a
  new inline ServiceInsuranceSection (no dialog wrapper; buttons type=button
  so they don't submit the parent service form)
- ClinicServicesPage: drop the separate 'پوشش بیمه' menu action and its
  standalone modal; render coverage inline under the service fields in the
  edit modal (edit only — needs the item uuid; create shows a hint)
- delete now-unused ServiceInsuranceModal.tsx
- fix undefined --primary-subtle token → --primary-soft
- test: coverage renders inline inside the service edit modal

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 15:58:32 +03:30
hamedandClaude Opus 4.8 7e1d887b72 feat(tags): match add-tag modal to tauri design (preset swatches + active toggle)
- TagsSettingsPage modal: replace native color input with 4 preset
  swatches, add 'وضعیت برچسب' active toggle, update labels and submit
  button to mirror tauri AddPurchaseSubTabModal
- TenantTagController::create now honors an optional 'active' flag
  (defaults true, non-breaking for existing callers)
- tests: backend active-flag case, frontend preset-color + inactive case
- docs/api/tag.md: document the new create 'active' field

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 15:39:45 +03:30
hamedandClaude Opus 4.8 f33c61365d refactor(settings): unify settings sidebar across all pages
SettingsLayout rendered its own role-gated aside while the subscription page
rendered PurchaseSubscriptionSidebar, so /admin/subscription and other settings
pages (sms-wallet, ...) showed two different settings menus. Make SettingsLayout
render the shared PurchaseSubscriptionSidebar and have SubscriptionPage use
SettingsLayout too, so every settings page shows one identical menu. menuForRole
/ SETTINGS_MENU are kept for the mobile settings list (SettingsMenuPage).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 15:25:10 +03:30
hamedandClaude Opus 4.8 a5618f6ee3 fix(subscription): remove double-centering gap beside main nav
The page wrapped its grid in a second maxWidth:1180/margin:auto on top of the
shell's already-centered .content (max-width 1480), leaving a ~150px gap
between the settings menu and the main navigation. Make the page full-width so
the settings sidebar sits flush against the main nav; trim the sidebar column
to 248px to match the app nav width.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 14:56:05 +03:30
hamedandClaude Opus 4.8 1c1cdfab07 fix(subscription): plan cards fill row, popular = professional
- Replace wrapping flex (maxWidth cap) with a fills-the-row grid
  (repeat(auto-fit, minmax(230px, 1fr))) so the three cards sit in one row
  and grow to the content width — removes the empty gap and stray wrap
- Move the most-popular highlight to the professional (top) plan, matching
  clinic-pro-tauri

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 14:49:58 +03:30
hamedandClaude Opus 4.8 37ddd47342 fix(subscription): sidebar layout, responsive cards, feature labels
- Drop leaking mobile tab strip; settings sidebar is now desktop-only (hidden
  lg:block) and pinned right via grid lg:grid-cols-[280px_minmax(0,1fr)],
  matching the SettingsLayout pattern
- Make plan cards responsive (flex 1 1 280px, min 250 / max 340) instead of
  fixed 300px width
- Fix secretaries pill bidi rendering (rtl, single label)
- Add Persian label for the 'insurance' plan feature

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 14:43:28 +03:30
hamedandClaude Opus 4.8 d67be26e8a feat: port purchase-subscription page from tauri to admin dashboard
Rebuild /admin/subscription to pixel-match clinic-pro-tauri's
setting/purchase-subscription while keeping the real subscription/payment API:

- New PurchaseSubscriptionSidebar (orange-accent settings sidebar, routes preserved)
- New subscriptionIcons (SVGs copied verbatim from tauri source)
- Rewrite SubscriptionPage: 522px plan cards (gradient blur, popular badge,
  secretaries pill, period toggle, dashed trial box), 365x104 current-plan card;
  wired to /subscription/plans, /subscription/my, /subscription/trial and the
  existing payment-gateway modal (no backend change)
- Expand tests: healthy/expiring/expired/no-sub, empty-plans, period toggle, buy modal

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 14:32:38 +03:30
hamed d9f96b68cd feat: port clinic dashboard components from clinic-pro-tauri
- Add NewAppointmentsTable for displaying today's appointments with status chips and formatted time.
- Implement TauriCharts for bar and line charts representing patient counts and revenue.
- Create TauriDashboardView to combine stat cards, charts, and new appointments list.
- Introduce TauriStatCards for displaying key statistics with icons.
- Add dashboardIcons for SVG icons used in stat cards.
- Implement tests for DashboardPage to ensure correct rendering and API calls.
- Create DashboardTodayAppointmentsTest to validate extended fields in today's appointments API response.
2026-07-14 13:54:50 +03:30
hamedandClaude Fable 5 165ececab4 feat(appointments): close the three remaining design gaps
1. شارژ کیف پول is now functional end-to-end. New owner-gated
   POST /api/v1/patient/{uuid}/wallet/charge creates a manual credit
   WalletTransaction (computed balance_after); the patient detail's wallet tab
   gains a top-up modal (PriceInput + description) and supports ?tab= deep
   links. The deposit sections of the create drawer, the edit page and the
   replace modal link to it via WalletChargeLink (record resolved by mobile).
2. جایگزینی نوبت now matches appointments-replace.pdf: patient search-or-new,
   بخش/سرویس/پرسنل selects prefilled from the appointment, deposit toggle +
   amount + charge link, read-only original date/time, status pick and notes —
   all through the general PATCH.
3. The confirmed-appointments table is paginated (20/page, client-side so the
   schedule view and doctor-tab derivation keep the whole day), resetting on
   date/doctor/filter changes. The page-local STATUS_META also adopts the
   design labels plus following_up/salon for the schedule cards.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 00:26:47 +03:30
hamedandClaude Fable 5 376e610260 feat(appointments): toolbar personnel filter (پرسنل را انتخاب کنید...)
Adds staffUuid to AppointmentFilters and a toolbar staff select that filters
the loaded day's rows client-side, matching appointments-table.pdf.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 00:09:08 +03:30
hamedandClaude Fable 5 f426a98ee6 feat(appointments): reserve list page (نوبت های رزرو شده) — phase D
ReserveAppointmentsPage lists day-level reserve entries
(/my/appointments?reserve=1, paginated) with the reserve-table.pdf columns
(مراجعه کننده/شماره تماس/تاریخ/سرویس/پرسنل/وضعیت/عملیات). The row menu offers
only the design's three actions — مشاهده (shared info modal), ویرایش (edit
page) and انتقال به لیست نوبت ها (shared transfer modal flipping is_reserve
back to a live slot). «نوبت رزرو» opens NewAppointmentDrawer in isReserve mode;
clinics pick the doctor first (doctor-list), doctors book for themselves via
dbUuid. Routed at /admin/appointments/reserve (before the :uuid route) and
added to the sidebar under نوبت‌ها for the three management role blocks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 00:07:00 +03:30
hamedandClaude Fable 5 f736e4acd8 feat(appointments): edit page + filters modal — phase C2/C3
- AppointmentEditPage (edit.pdf): full-page edit of بخش/سرویس/پرسنل, Jalali
  date + start/end time, deposit, status and notes; hydrates from
  GET /appointment/{uuid} and saves through the general PATCH with the
  optimistic-lock version. Routed at /admin/appointments/:uuid/edit (the
  actions-menu ویرایش target).
- AppointmentFiltersModal (filter-desktop.pdf): name/national-code search,
  بخش/سرویس selects, six status checkboxes (لغو شده covers both cancel
  reasons), gender radios, حذف همه reset. Filtering is client-side over the
  loaded day via the pure applyAppointmentFilters; toolbar gains the filter
  button with an active indicator.
- /my/appointments rows now include patient_national_code and patient_gender
  so the filters have data to match on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 00:02:22 +03:30
hamedandClaude Fable 5 91ea1b02aa feat(appointments): rich create drawer (اضافه کردن نوبت جدید) — phase C1
NewAppointmentDrawer implements add.pdf: patient search-or-new (patient-list
search), بخش/سرویس/پرسنل selects (service-sections, service-items, staff),
Jalali date + default-duration with auto end-time, deposit toggle + PriceInput,
status pick (applied via the status endpoint after create) and notes. The
toolbar «نوبت جدید» button now opens it instead of only hinting at slot click;
the slot-click quick modal stays. isReserve mode (day-level, no time fields)
is reused by the upcoming reserve list page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 23:55:13 +03:30