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>
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>
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>
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>
- 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>
- 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>
- 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>
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>
For the doctor and clinic roles, collapse the subscription section into one
'تنظیمات' item (Cog icon) pointing at /admin/subscription, matching the tauri
main sidebar. Remove the items that now live in the in-page settings submenu
(insurance-pricing, clinic-services, sms-wallet) from the main nav so they are
not duplicated. Secretary (no settings page) is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Give the subscription sidebar its own nav list copied from clinic-pro-tauri's
PurchaseSubscription navItems (order and labels), dropping 'مدیریت پزشک' (it
belongs in the main nav). Items are shown ungated to mirror the source; the
'تنظیمات' (security) section has no doctor/clinic route yet so it renders
disabled. SETTINGS_MENU / SettingsLayout (other pages) are left untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Flip the settings menu to dir=rtl with right-aligned title, search and rows so
the Persian labels read right-to-left.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
- 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>
- 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>
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>
- 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.
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>
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>
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>
- 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>
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>
Frontend for the Figma عملیات menu on the confirmed-appointments table:
- AppointmentActions composite: six-item row menu (ویرایش، ثبت سرویس، مشاهده،
جا به جایی، انتقال به لیست رزرو، جایگزینی) plus the four modals it opens.
ثبت سرویس and the info modal resolve the patient record via the patient-list
search (mobile) to reuse the existing wallet endpoint and NewSessionPage.
- Info modal mirrors appointments-info.pdf: start time, duration, phone,
بخش/سرویس/پرسنل, wallet balance, status dropdown, مشاهده پرونده.
- Move/transfer/replace modals PATCH the new general update endpoint with
optimistic-lock version; transfer uses day-level midnight slots.
- Status labels/transitions updated to the design set (ثبت شده/قطعی شده/
در حال پیگیری/سالن/ویزیت شده/لغو شده) in AppointmentStatusDropdown and
StatusBadge; Appointment type gains the new workflow fields; the table gains
سرویس/پرسنل/عملیات columns.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a record-scoped PatientCall entity (subject, summary, outcome
success/missed, called_at, personnel) with its repository and three
owner-gated endpoints on PatientController:
GET /patient/{uuid}/calls — call log, newest first, optional ?outcome
POST /patient/{uuid}/call — log a call (subject required)
DELETE /patient/call/{uuid} — delete an entry
Wire the previously-placeholder "کال سنتر" tab as a CallCenterTab: a register
form (date/time/subject/summary + success/missed toggle, personnel taken from
the logged-in user) beside a filterable call history (all / success / missed).
With this every patient-detail tab is now backed by a real endpoint, so the
generic Placeholder is no longer reachable. PatientCallTest covers create/list/
delete, the outcome filter, the invalid-outcome fallback, and ownership scoping.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The generic wallet/payment endpoints are bound to #[CurrentUser] (the
requester's own money), so they cannot serve a record owner viewing a patient's
finances. Add three record-owner-gated read endpoints on PatientController that
reuse the existing repositories:
GET /patient/{uuid}/payments — paginated gateway payments (?status)
GET /patient/{uuid}/wallet — balance + 10 recent transactions
GET /patient/{uuid}/wallet/transactions — full paginated ledger
Wire the previously-placeholder "پرداختها" and "کیف پول" tabs on the patient
detail page: payments via the shared TabList, wallet via a new WalletTab (balance
card + credit/debit ledger). PatientFinancialsTest covers the happy path, the
credit−debit balance, and ownership scoping (404 for a different owner).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reuse the existing NewSessionPage (service section/item + insurance coverage +
payment flow → POST /patient/{recordUuid}/session) from the new patient detail:
add a patients-scoped route /admin/patients/:recordUuid/session/new and a
"سرویس جدید" action on the services tab. The multi-step visual restyle and the
standalone invoice-issuance screen remain a follow-up (the underlying
session/billing endpoints already exist).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a patient message/communication log: a new PatientMessage entity
(record-scoped, CASCADE) + repository, and owner-scoped endpoints
(GET messages, POST message, DELETE message) with a validated channel
(sms/note/call/email). Wire the "پیامها" tab in PatientDetailPage
(send box + list + delete). PHPUnit covers create/list/delete + ownership
+ validation; Vitest covers the tab. API docs updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add patient medical-exam entries: a new PatientMedicalRecord entity
(record-scoped, CASCADE) + repository, and owner-scoped CRUD endpoints
(GET list, POST create, PATCH, DELETE) under /api/v1/patient. Wire the
"پرونده پزشکی" tab in PatientDetailPage (list + add/edit modal with title,
date and notes + delete). PHPUnit covers CRUD + ownership + validation;
Vitest covers the tab. API docs updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add patient file attachments: a new PatientAttachment entity (record-scoped,
CASCADE) + repository, and endpoints GET /patient/{uuid}/attachments,
POST /patient/{uuid}/attachment (raw-body upload) and DELETE
/patient/attachment/{uuid} (owner-scoped). Factor the shared raw-body upload
logic into FileUploadService. Wire the "ضمیمه" tab in PatientDetailPage
(upload + list + delete). PHPUnit covers list/delete/ownership; Vitest covers
the tab. API docs updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a standalone PatientDetailPage at /admin/patients/:uuid: a header + the
9-tab case-file bar (services, info, appointments, payments, wallet, messages,
call-center, attachments, medical-record). The info, services (sessions) and
appointments tabs are wired to existing endpoints; the remaining tabs render a
placeholder until their backends land (phases B2–B5). The list "مشاهده" action
now opens this detail page.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebuild the patient records (پروندهها) area, phase A of the Figma redesign:
- BE: add a clinic-scoped `record_number` and a TenantTag `tags` M2M to
PatientRecord (migration + EAGER-hydrated collection). POST /patient and
PATCH /patient/{uuid} now accept `record_number` and tenant-scoped `tags`
(foreign tag → 422); demographic fields (gender, date_of_birth,
referral_source, description) continue to live on UserProfile via PATCH.
- FE: new PatientsListPage (table + card views, search, pagination, tags
column, "تشکیل پرونده") at /admin/patients, and PatientRecordFormPage
(create/edit) that POSTs the record then PATCHes the demographics. Point
the sidebar "پرونده" entry to the new list.
Phases B–E (tabbed patient file, service stepper, invoice, payments/wallet,
call-center) follow. Backend covered by PHPUnit, FE by Vitest.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an optional `roles` filter to the settings menu and hide items that don't
apply to the current user's role, so a doctor no longer sees "مدیریت مطب"
(clinic-only) and a clinic no longer sees "مدیریت پزشک" / "مدیریت نوبت دهی"
(doctor-only) — avoiding menu entries that just redirect. Both the desktop
shell (SettingsLayout) and the mobile list (SettingsMenuPage) filter via the
shared `menuForRole` helper.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fill the three previously-placeholder settings sections so every menu item
is now a real page inside the settings shell:
- حساب کاربری: new authenticated POST /api/v1/user/change-password
(verifies current password, ≥8 chars, must differ) + account page with a
profile summary and change-password form.
- برچسبها: new per-tenant TenantTag domain (entity/repo/controller +
migration) with tenant-scoped CRUD at /api/v1/tenant-tag(s), plus a tags
management page (list + color + add/edit/delete).
- مدیریت نوبت دهی: export the existing WeeklyScheduleTab from
DoctorDetailPage and reuse it in a standalone AppointmentSettingsPage
(current doctor's uuid + addresses).
Wire all three menu entries to their routes. Backend covered by PHPUnit
(change-password, tenant-tag CRUD + ownership); FE covered by Vitest.
API docs updated (auth.md, tag.md).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wrap the existing settings-area pages — doctor profile (مدیریت پزشک),
insurance pricing (بیمه), payment report (پرداخت), SMS wallet (پیامکها),
secretaries (منشی) and clinic info (مطب) — in SettingsLayout so they appear
under the settings sub-navigation like the Figma design, with the matching
menu item highlighted. Wire the doctor/clinic menu entries to their routes.
The نوبتدهی / برچسبها / حساب کاربری entries stay as disabled placeholders
until they have their own pages/designs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render the clinic services page (sections → services) inside the settings
sub-navigation shell (SettingsLayout, "خدمات" active) to match the Figma
settings design. Restyle section cards to show the service count and a
status toggle with edit/delete actions, and service cards with labelled
price/duration and personnel chips.
A service can now have multiple personnel: add an additive many-to-many
ServiceItem↔ClinicStaff (staffMembers, EAGER) while keeping the legacy
single `staff` column mirrored for backward compatibility. Endpoints accept
`staff_uuids[]` (falling back to the legacy single `staff_uuid`) and return
`staff_members[]`; the section list now reports `items_count`.
Backfill-safe: pre-migration rows fall back to the single staff in toArray.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a doctor/clinic settings sub-navigation shell (SettingsLayout) with
"خرید اشتراک" as its first section, plus a mobile settings-list page.
Rebuild the plan-selection page with a per-plan billing-period toggle,
single price, most-popular badge and a current-plan status banner.
Add a payment-success page that reads the gateway return params
(?payment_uuid&status), shows the transaction receipt and the newly
active plan, and redirects to the plans page with a toast on any
non-success status.
Frontend only — reuses the existing /api/v1/subscription/* and
/api/v1/subscription-payment endpoints; no backend or API-doc changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Backend:
- Add profile columns field_of_study, province_id, city_id, postal_code,
referral_source (UserProfile + migration).
- Extend PATCH /api/v1/patient/{uuid} to persist all demographic fields
and return them in the patient profile payload.
- Support editable mobile (login identifier): validation, uniqueness,
User.setMobileNumber, new ERR_PROFILE_002.
- Update docs/api/patient.md.
Frontend:
- New reusable Input, Field, and PatientRecordInfoForm (RHF + Zod).
- usePatient/useUpdatePatient hooks and patientForm mapping helpers.
- Extend the existing "info" tab in MyPatientsPage to the full field set
via the shared form (province/city/insurance options, Jalali date).
Tests: Patient entity + PATCH integration (PHPUnit); form, hooks, and
mapping helpers (Vitest).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>