- Refactor color palette in `ui-design-spec.md` to utilize CSS variables exclusively, eliminating fixed hex values and Tailwind utility classes.
- Complete dark mode implementation in `uiStore.ts`, ensuring proper theme application via `applyTheme()` and `applyBrand()`.
- Create `admin-theme-dark-light-audit.md` to document the transition process, outlining issues with inline styles and fixed colors.
- Introduce `theme-tokens.test.ts` to enforce rules against fixed hex colors and ensure compliance with the design system.
- Update various components and styles to replace inline styles and fixed colors with CSS variables, ensuring consistent theming across light and dark modes.
- Ensure all changes maintain visual integrity in both light and dark modes, with a focus on accessibility and contrast standards.
An appointment can now carry the insurance it is billed with: the service kind
(outpatient/inpatient) and the basic insurance. Confirming it no longer hands the
whole amount to the patient — the visit is split through BillingCalculator with the
coverage percent of that service kind, and the choice travels to the encounter and
the invoice built from it.
The enabled service kinds are a tenant-wide setting (all of that tenant's
insurances share it), so a tenant covering only one kind is never asked which one:
the panel resolves it the same way the server does.
- add tenant_service_category_settings + TenantServiceCategoryService, exposed on
the existing insurance-pricing endpoint (service_categories,
default_service_category); at least one kind must stay enabled
- add appointments.insurance_service_category / insurance_base_id with
AppointmentInsuranceService validating them against the tenant's own settings
and active contracts (basic only), accepted by PATCH and by confirm
- snapshot the kind on patient_sessions and invoices; the visit's coverage rule is
resolved per kind (services keep using their own ServiceItem.service_category)
- lib/insuranceShares becomes the single client-side mirror of BillingCalculator,
shared by the confirm modal, the appointment edit page and the session form
- surface the selection: confirm modal (with live shares), turns timeline chip,
appointment edit page, patient record service card and invoice summary
- the session form shows the insurance block whenever the tenant has an active
contract and prefills the patient's own insurance, so it can be changed
- fix: the confirm modal showed a zero visit price when the appointment had none —
it now falls back to the tenant's free-visit price like the server
- fix: useServiceCategories read one level too shallow, so Persian labels never
arrived and raw enum keys leaked into the contract summary
- fix: BlogsPage test asserted the public blogs endpoint after the page moved to
the admin one
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Adjusted the calculation of payable amounts in PaymentStep to align with server logic, ensuring overpayments are handled correctly.
- Enhanced DetailsStep to include consumables in the itemized cost breakdown, ensuring consistency with patient share calculations.
- Updated tests for SessionPaymentPage to validate new behavior regarding overpayments and consumable listings.
- Modified PatientController to register SessionPayment correctly when settling sessions via wallet, preventing double charges.
- Refactored WalletService to remove outdated methods and ensure wallet transactions reflect the correct amounts after discounts.
- Improved accessibility in SearchableSelect component by adding aria labels and ensuring proper role attributes for screen readers.
- Updated styles to ensure minimum touch targets meet WCAG guidelines for mobile usability.
- Consolidated the calculation of patient and insurance shares into a single method using BillingCalculator.
- Introduced new fields in PatientSession to store breakdown of insurance shares and patient share.
- Updated the API responses to include the new fields for consistency across payment, invoice, and claims dashboard.
- Added migration to backfill existing sessions with appropriate values for the new fields.
- Implemented tests to ensure the correctness of the new logic and verify that the breakdown sums to the gross total.
- Redesigned the claims dashboard to provide a more user-friendly overview of patient claims and their statuses.
- SessionServiceCard menu gains «ویرایش» and «تاریخچه تغییرات» items.
- SessionAuditModal shows the session's change history (field, op badge,
old->new, actor, time) from /session/{uuid}/audit-log.
- PaymentStep payment rows get edit (modal) + delete (confirm) controls for
non-wallet payments, calling the new PATCH/DELETE payment endpoints.
- CreateStep accepts an editSession prop (prefill + PATCH); EditSessionPage
reuses it at /patients/:recordUuid/session/:sessionUuid/edit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SessionServiceCard's '...' icon becomes a real dropdown with «مشاهده فاکتور»
and «آرشیو»/«خروج از آرشیو» (click-outside close), plus an «آرشیو» badge on
archived cards. PatientDetailPage adds a فعالها/همه/آرشیو segmented filter on
the services tab (default active), threads the filter into the sessions query,
and wires the archive action to PATCH /session/{uuid} { archived }.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each recorded payment row (PaymentStep + DetailsStep) now shows the payment
date+time (paid_at, Jalali via formatDateTime, falling back to created_at) and
the user who recorded it (created_by_name) beneath the method/amount line. Both
fields were already in the API payload. Add created_at to SessionPaymentEntry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PaymentStep now loads /session/{uuid}/discount-suggestions and lets the
operator apply a suggested rule (PATCH discount_rule_uuid) or remove it,
alongside the existing manual discount. Adds an amount summary (before /
discount + source rule label / final payable). Verified end-to-end.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DetailsStep now renders the appointment's visit date/time first (from
session_at, falling back to created_at) and an itemized cost table (visit +
each service line with its line total) plus the grand total. Extend
SessionCardData with session_at, services_total_rials, and per-line price
fields already returned by the session API.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The admin SPA never called POST /billing/invoices, so every session had
invoice_uuid = null and the view-invoice buttons on the patient services
tab (and MyPatients visit modal) were permanently disabled. Add a shared
useIssueInvoice hook (idempotent create + finalize when draft) and wire
it into:
- DetailsStep: the wizard's final step now really issues the invoice
- SessionServiceCard / PatientDetailPage: clicking view-invoice on a
session without an invoice issues it first, then opens the summary
- MyPatientsPage visit modal: same, replacing the dead disabled button
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Port the tauri /files/create-service page (payment mode) to the admin SPA
and back it with real multi-part session settlement:
Backend:
- New SessionPayment entity (session_payments table): partial payments
per session with method (wallet/pos/cash/card), amount, paid_at, actor
- PatientSession: settlement discount (percent/fixed), discount_rials,
paid_at, payments relation; remaining debt derived from
final - discount - paid total
- POST /api/v1/session/{uuid}/payments: register a partial payment;
wallet method debits the patient wallet; zero remaining marks paid
- PATCH /api/v1/session/{uuid}: accepts discount_type/discount_value
(null removes) and paid_at, backward compatible
- New error codes: ERR_SESSION_PAYMENT_INVALID/_EXCEEDS,
ERR_SESSION_DISCOUNT_INVALID
- Migration + 14 functional tests (partial/full/wallet/exceed/discount)
Frontend (admin):
- SessionPaymentPage: two-step stepper (پرداخت ← جزییات) ported from
tauri AddService payment mode — service cost, settlement discount
input, Jalali payment date, wallet balance, 4-method payment accordion,
paid-list box, details summary
- SessionStepper + stepper/payment icons ported verbatim from tauri SVGs
- «تکمیل پرداخت» on SessionServiceCard now navigates to the payment page
(replaces the small settle modal on PatientDetailPage)
- Routes for patients/ and my-patients/ variants; vitest coverage
- docs/api/patient.md updated
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>