Commit Graph
100 Commits
Author SHA1 Message Date
hamedandClaude Opus 4.8 ef97b2b249 feat: unify wallet with real payment methods, full transaction transparency, pay-session-from-wallet
Address wallet feedback: use the clinic's real payment infrastructure,
redesign the tab to match the admin panel, and make every wallet movement
fully auditable.

Backend:
- WalletTransaction: add createdBy (acting user) + createdByName, payment_method,
  reference, status; toArray exposes them (migration Version20260716083939).
- WalletService (Settlement): balance/charge/withdraw + settleSessionFromWallet,
  records actor/method/reason; insufficient balance throws ERR_WALLET_INSUFFICIENT.
- PatientController: charge/withdraw delegate to WalletService and accept
  payment_method/reference; PATCH /session/{uuid} with payment_method=wallet
  debits the patient's final share from the wallet (reference=session:{uuid}).
- docs/api/patient.md updated.

Frontend:
- Wallet modal redesigned to panel style (no gradient); payment method now uses
  the clinic's real bank accounts + POS devices (usePaymentMethods) plus cash.
- Wallet tab: panel balance card + DataTable ledger with columns مبلغ/نوع/روش/
  دلیل/ثبت‌کننده/تاریخ/ساعت/وضعیت + همه/واریزی/برداشت filters.
- Session card «تکمیل پرداخت» opens a payment-method chooser incl. کیف پول.

Tests: backend transparency + session-from-wallet (success/insufficient/cash);
frontend modal (real methods, toman→rials) + wallet tab + settle chooser.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 12:22:37 +03:30
hamed 22474653b5 chore: update graphify graph 2026-07-16 11:57:00 +03:30
hamedandClaude Opus 4.8 f028d6841a feat: port wallet charge/withdraw modal from tauri to patient admin page
Add manual wallet withdrawal (debit) endpoint mirroring the offline app's
balance guard, and rebuild the patient کیف پول tab around a single
charge/withdraw toggle modal (quick amounts, تومان→ریال conversion,
transaction filters).

Backend:
- POST /api/v1/patient/{uuid}/wallet/withdraw — creates a debit
  WalletTransaction; 422 ERR_WALLET_INSUFFICIENT when amount exceeds balance.
- ErrorCodes: ERR_WALLET_INSUFFICIENT ('موجودی کیف پول کافی نیست').
- docs/api/patient.md updated.

Frontend:
- usePatientWallet hook (balance + charge/withdraw mutations).
- WalletTransactionModal (toggle, quick amounts, UI-only payment fields).
- WalletTab: charge button, همه/واریزی/برداشت filters.

Tests: backend withdraw success/insufficient/non-positive/ownership;
frontend modal + wallet tab interactions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 11:56:39 +03:30
hamed 4a70c87a8b chore: update graphify graph 2026-07-16 11:41:05 +03:30
hamedandClaude Opus 4.8 069189863c feat: port پرداخت‌ها (payments) tab from tauri to patient detail page
Replace the flat gateway-payment list on the patient detail «پرداخت‌ها» tab with
the session-grouped accordion design ported from clinic-pro-tauri PaymentsSection:

- New SessionPaymentAccordion mirrors the tauri accordion: header (service, date,
  final price, پرداخت شده/تسویه نشده badge) + a settlement line (date, amount,
  method, personnel=doctor) or the «هیچ پرداختی ثبت نشده است.» empty message.
- New PaymentsTab reuses the already-fetched sessions query (real model = one
  payment_method per session) — no extra request, no backend change, no new API.
- Add FilesServicePaymentsCheck icon (verbatim from tauri).
- Remove the now-unused paymentsQ (gateway list), PAYMENT_STATUS map and the dead
  TabList helper (both its callers replaced by the ported card/accordion tabs).
- Tests: SessionPaymentAccordion (paid/unpaid/collapsed/toggle) + updated the page
  payments-tab test to assert session accordions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 11:40:51 +03:30
hamed b82ab4db9c chore: update graphify graph 2026-07-16 11:30:35 +03:30
hamedandClaude Opus 4.8 1a783971c9 feat: port نوبت‌ها (appointments) tab from tauri to patient detail page
Replace the placeholder row list on the patient detail «نوبت‌ها» tab with the
card-grid design ported pixel-for-pixel from clinic-pro-tauri TurnsSection:

- New AppointmentTurnCard mirrors tauri TurnsCard (success icon, title, date/time
  chips, personnel, status). Status uses the live AppointmentStatusDropdown
  instead of the tauri mock.
- New AppointmentsTab in PatientDetailPage: sort/filter toolbar (client-side) +
  reserve/new buttons linking to existing /admin/appointments pages + card grid.
- Add CalendarD/ClockP/UserD/StatusGlobe icons (verbatim from tauri).
- Backend: expose version on GET /patient/{uuid}/appointments so the status
  dropdown can optimistic-lock. No new endpoint.
- Tests: PatientAppointmentsTest (shape/version/order/empty/ownership) +
  AppointmentTurnCard + tab data/empty cases. docs/api/patient.md updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 11:30:12 +03:30
hamed 7b87fda8f9 chore: update graphify graph 2026-07-16 11:16:40 +03:30
hamedandClaude Opus 4.8 f5b0ddc69e fix: SearchableSelect matches value across string/number types
Insurance option values are strings (String(insurance_id)) while the patient
profile prefill is a number, so strict === matching left بیمه پایه/تکمیلی
showing the placeholder on load — the saved insurance was invisible and looked
unsaved even though PATCH persisted it. Match with String(o.value) ===
String(value) so numeric prefills bind to string-valued options (and vice
versa); null/'' still selects nothing. Verified live: selects now display the
saved insurance after reload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 11:16:22 +03:30
hamed 2e2b63f72d chore: update graphify graph 2026-07-16 10:59:43 +03:30
hamedandClaude Opus 4.8 46ee24d101 feat: add supplementary insurance select to patient record info form
The «اطلاعات پرونده» form only exposed basic insurance («نوع بیمه»). Add a
«بیمه تکمیلی» select next to it, wired to the supplementary insurances from
insurance-pricing. Backend PATCH /api/v1/patient/{uuid} already accepts
supplementary_insurance_id (UserProfile entity + controller) — frontend-only:
schema field, form select, profileToFormValues/formValuesToPayload mapping,
PatientProfileUpdate type, and the supplementary option passed from both the
case-file info tab (PatientDetailPage) and MyPatientsPage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 10:59:23 +03:30
hamed 8feaf0f22a chore: update graphify graph 2026-07-16 10:53:05 +03:30
hamedandClaude Opus 4.8 9638f363af feat: wire editable «اطلاعات پرونده» form into patient case-file info tab
Port tauri /files-services FileInfoSection into PatientDetailPage's info
tab. The tab previously rendered a stripped read-only InfoRow list; it now
renders the inline editable PatientRecordInfoForm (18 fields + ثبت اطلاعات),
matching the tauri source. Reuses the existing form component, patientForm
helpers, and the already-present patient/provinces/cities/insurance-pricing
endpoints (no new API). PATCH /api/v1/patient/{uuid} on submit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 10:52:31 +03:30
hamed d12259be15 chore: update graphify graph 2026-07-16 10:43:44 +03:30
hamedandClaude Opus 4.8 04cc36c33a fix: clean up selected-service chip layout in ServiceSlotPicker
Replace the .field-wrapped duration input (whose min-width + inner label
overflowed the fixed 92px box) with a self-contained inline duration editor;
drop flex-wrap and let the section->service name truncate with ellipsis so
each chip stays on one tidy row.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 10:43:39 +03:30
hamed 78396d3275 chore: update graphify graph 2026-07-16 10:41:24 +03:30
hamedandClaude Opus 4.8 e00fe997f9 feat: section-based service picker + per-appointment duration override (service mode)
Service-booking mode now selects services by section like slot mode:
appointment-booking-services returns service_section per item; ServiceSlotPicker
groups by section (SearchableSelect), accumulates picks across sections into a
removable 'section -> service' chip list.

Secretaries can override a service's duration for a single appointment without
changing the service default: appointment-service-slots accepts durations[uuid]
and both create endpoints accept service_durations; the override drives total
duration and slot_end. Online (patient) booking is unaffected — it never sends
overrides. Backend + frontend tests and docs updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 10:41:15 +03:30
hamed af6da197dc chore: update graphify graph 2026-07-16 10:18:16 +03:30
hamedandClaude Opus 4.8 029b5f632e feat: section-then-service picker with cross-section accumulation
Rework slot-mode service selection: pick a section, its services show as a
checkbox list, and chosen services collect into a removable 'selected'
chip list that persists when switching to another section (services from
multiple sections accumulate). Changing the section no longer clears the
selection. Add a test covering multi-section accumulation and chip removal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 10:18:10 +03:30
hamed 08aa3a78b8 chore: update graphify graph 2026-07-16 10:10:56 +03:30
hamedandClaude Opus 4.8 4642506c0f feat: support multiple services per appointment (checkbox selection)
Appointments could only reference a single service (ManyToOne). Add an
appointment_service_items join table (ManyToMany) so an appointment can
carry several services; the first stays the primary service_item for
backward compatibility, and toArray now also returns service_items[].

Both create endpoints (my/appointment, admin/appointment) accept
service_item_uuids[] and attach all of them. A new duration_from_services
flag gates the slot_end recompute: service-booking mode sends it true
(slot_end = start + Σ durations); slot mode omits it so the manual end
time is preserved. The admin endpoint previously ignored services entirely.

Frontend: in slot mode the single service dropdown becomes a checkbox list
filtered by the selected section (multi-select); service mode sends the
duration flag. Migration + backend/entity tests + docs updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 10:10:47 +03:30
hamed d76fd73529 chore: update graphify graph 2026-07-16 09:57:11 +03:30
hamedandClaude Opus 4.8 3e8126c520 fix: return patient national code from profile in patients list
National code is stored on the profiles table, not users, so the patients
search returned null user_national_code for patients that actually have one
— which blocked selecting an existing patient on the appointment create
form. Backfill user_national_code from the profile (batch query) in the
list endpoint. On the create page, show a picked patient's stored national
code read-only and only prompt for input when the record genuinely lacks
one. Add backend tests and update docs/api/patient.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 09:57:03 +03:30
hamed 110c210cf4 chore: update graphify graph 2026-07-16 09:45:13 +03:30
hamedandClaude Opus 4.8 e1fb63eb0f feat: add DigitInput component; force English digits for phone & national code
New reusable DigitInput normalizes Persian/Arabic digits to English on
input, strips non-digits, enforces maxDigits, and is always LTR + numeric
keyboard. Use it for the phone and national-code fields on the appointment
create page (phone previously kept raw Persian digits; national code lost
Persian digits to the \D strip).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 09:45:04 +03:30
hamed b2347f00e7 chore: update graphify graph 2026-07-16 09:39:40 +03:30
hamedandClaude Opus 4.8 bc4030251d fix: allow submit when picking an existing patient
Backend requires a valid national code for every appointment, but a picked
patient record may have none stored. Show a selected-patient card with an
editable national-code field (prefilled from the record) so submit can
enable. Add happy-path and boundary tests for the picked-patient flow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 09:39:33 +03:30
hamed 10adfa3b15 chore: update graphify graph 2026-07-16 09:33:24 +03:30
hamedandClaude Opus 4.8 a40fb7e598 feat: toggle new-patient form on appointment create page
Show name/phone/national-code fields only after clicking 'مراجعه کننده جدید';
hide the existing-patient search while in new-patient mode, with a
'انتخاب از لیست موجود' link to switch back. Update tests to click the
toggle before filling the fields.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 09:33:16 +03:30
hamed 6e040402e1 chore: update graphify graph 2026-07-16 09:28:25 +03:30
hamedandClaude Opus 4.8 54bdc73f37 fix: correct deposit section layout on appointment create page
Move switch to its own row; render amount field (wrapped in .field for a
proper bordered box) and wallet-charge button on a following aligned row.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 09:28:19 +03:30
hamed a6c11a20bd chore: update graphify graph 2026-07-16 09:18:53 +03:30
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 b7730f545a fix(appointment): update EmptyCard to display 'افزودن نوبت سریع' for better clarity 2026-07-16 09:05:26 +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 ac4a430564 feat(appointment): add booking services endpoint and update security configuration for public access 2026-07-15 23:48:38 +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 ad94c165e8 feat(appointment): add service mode functionality and update API documentation for service-based booking 2026-07-15 23:22:57 +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 6904361e32 feat(appointment): update patient name handling to prioritize existing profile name for new appointments 2026-07-15 22:35:33 +03:30
hamed 13bf9453e5 feat(appointment): ensure existing profile name is used over modal input for patient name 2026-07-15 20:33:15 +03:30
hamed d91867bd63 fix(appointment): resolve issue with reserved slots incorrectly shown as available 2026-07-15 19:13:27 +03:30
hamed de6fe1bd56 feat(appointment): update patient identification to use national code from profile and enhance appointment creation logic 2026-07-15 18:46:56 +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
hamed f378bf58e6 Add AST JSON representation for BookingScopeTest.php with nodes and edges 2026-07-15 18:14:59 +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 141ce478a2 chore: update graphify graph 2026-07-15 17:45:07 +03:30
hamedandClaude Opus 4.8 1aa6794786 feat: port tauri header top-menu to admin topbar
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>
2026-07-15 17:44:47 +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
hamedandClaude Opus 4.8 810293764a chore: update graphify graph
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:06:42 +03:30
hamedandClaude Opus 4.8 62e0cdb518 feat(admin): add orange rgb(241,119,50) as an exact brand-color option
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>
2026-07-15 17:06:24 +03:30
hamedandClaude Opus 4.8 89ebeb8fce style(admin): orange accent for شخصی‌سازی panel
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>
2026-07-15 16:55:53 +03:30
hamedandClaude Opus 4.8 edf3cea51f chore: update graphify graph
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 16:48:58 +03:30
hamedandClaude Opus 4.8 0a78bf7a6b style(admin): align design tokens to clinic-pro-tauri
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>
2026-07-15 16:48:25 +03:30
hamed 5c15a4dd7f feat(services): add services menu item to sidebar and update related components 2026-07-15 16:35:02 +03:30
hamed 704e69f05f chore: update graphify graph 2026-07-15 16:20:34 +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
hamed ab2904b81a chore: update graphify graph 2026-07-15 16:13:41 +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
hamed 41e193ab83 chore: update graphify graph 2026-07-15 16:07:15 +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
hamed ef6017e688 chore: update graphify graph 2026-07-15 15:46:00 +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
hamed bf9fce4e05 chore: update graphify graph 2026-07-15 15:33:24 +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 7ea2cb4ab2 fix: render inventory actions menu in a portal so it is not clipped
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>
2026-07-15 14:07:47 +03:30
hamed 7819068e82 chore: update graphify graph 2026-07-15 13:48:47 +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 f1e9129a2c Add AST JSON representation for insurance API documentation
- 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.
2026-07-15 13:25:13 +03:30
hamedandClaude Opus 4.8 d7cb9ea5a3 feat(insurance): redesign insurance management page to match Figma
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>
2026-07-15 13:23:38 +03:30
hamed e94f832c8a fix: adjust styles for PermissionAccordions component for better usability 2026-07-15 12:47:42 +03:30
hamed 3634d37cb6 chore: update graphify graph 2026-07-15 12:28:52 +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
hamed f2029a5ad4 chore: update graphify graph 2026-07-15 12:23:46 +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
hamed 57c5383baf chore: update graphify graph 2026-07-15 11:51:46 +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
hamed d89068e668 chore: update graphify graph 2026-07-15 11:39:57 +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
hamed cac2e8b46a chore: update graphify graph 2026-07-15 11:17:00 +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 0e057e0c66 chore: update graphify graph
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 10:36:54 +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 8df616683d chore: update graphify graph
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 09:39:30 +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 2220c516d7 chore: update graphify graph
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 09:31:57 +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 99047458b6 chore: update graphify graph
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 19:41:18 +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 4edeffe325 chore: update graphify graph (force)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 19:00:58 +03:30