Commit Graph
63 Commits
Author SHA1 Message Date
hamed 3ffab2bbd0 feat(stepper): implement multi-step wizard for appointment confirmation process 2026-08-09 09:12:00 +03:30
hamed 948f59827a feat(appointments): implement multi-step wizard for appointment booking modal 2026-08-09 08:53:55 +03:30
hamed b49abee52f refactor: update pricing input handling to use PriceInput component
- Replaced raw input fields for pricing with PriceInput component across various forms and modals to ensure consistent formatting and accessibility.
- Updated tests to reflect changes in pricing input handling, ensuring values are displayed in toman with proper formatting.
- Enhanced accessibility by adding aria-labels and aria-invalid attributes to PriceInput components.
- Adjusted UI elements to improve layout and user experience, particularly in forms related to service items and scheduling.
- Changed labels from "نمایش در نوبت‌دهی" to "نمایش در نوبت‌دهی آنلاین" for clarity.
2026-08-09 08:38:23 +03:30
hamed 6876135a53 feat: add BlogBodySanitizer for HTML sanitization on article save
- Implemented BlogBodySanitizer to clean HTML content before saving articles, ensuring security against XSS attacks.
- Added tests for BlogBodySanitizer to verify that unsafe tags and attributes are stripped from the content.
- Introduced ApiLeastPrivilegeTest to ensure that unauthorized users cannot access sensitive API routes, maintaining strict access control.
2026-08-07 21:13:38 +03:30
hamedandClaude Opus 5 7c3407b0b3 refactor(admin): split the secretary form from its permissions into two modals
Adding a secretary meant deciding all 17 permission resources in the same
dialog. The full-height capture showed the form running past 1300px with the
save button below 16 accordions, and the dynamic registry makes that worse: every
page added in future lengthens this one modal.

The add/edit modal now carries only doctors, profile and address, and fits on
screen with its footer visible. Permissions move to SecretaryPermissionsModal,
reachable from a row action and opened automatically right after a successful
add, since a new secretary starts on the role defaults and the owner usually
wants to set them.

Neither create nor update sends permissions any more — the backend seeds the role
defaults on create, and the permissions modal owns the writes, fanning out over
every link row so a secretary shared across doctors stays consistent.

PermissionAccordions moves to components/ui as a shared component. Sections now
start collapsed with a granted/total badge on each header, so the panel opens at
a fixed height and still says which sections are on.

Two design-system slips caught by re-screenshotting rather than by the audit:
- a text button as a third row action pushed the name column out of the table, so
  the desktop row uses an icon with a title and the mobile card keeps the label
- .btn.secondary is not defined in styles.css (variants are primary/ghost/soft/
  danger/accent), so it renders as a bare .btn. Used ghost here. 25 other files
  have the same dead class; left alone as a separate sweep.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 19:55:32 +03:30
hamedandClaude Opus 5 ddd5f8f75a feat(permissions): render both permission forms from the catalog, fix borrowed gates
The three hardcoded resource lists in the admin panel are gone. MySecretariesPage,
SecretariesPage and DoctorPermissionsModal now render from
GET /api/v1/permission-catalog, so a resource added to the backend registry shows
up in all of them with no frontend change. Each has a test that proves exactly
that by adding a resource to the mock and asserting it renders.

SecretaryPermissions was an interface with a field per resource, which made
"dynamic" impossible in TypeScript — every new resource would have been a compile
error. It is now an open map. Only two files consumed it.

The borrowed gates are corrected:
- five resource pages moved off appointment_settings onto their own 'resources'
- treatment-cases moved off appointments onto 'treatment'
- service-categories moved onto 'services', which is what ServiceCatalogController
  actually manages (categories, item groups, service relations) — not resources

TreatmentCaseController had no permission gate at all, only IS_AUTHENTICATED_FULLY,
so any secretary could read and edit treatment cases. All seven of its actions are
now gated on treatment view/update.

ResourcePermissionTrait takes the resource from an overridable method instead of
hardcoding appointment_settings. HolidayController overrides it back, since the
holidays page really is appointment settings. The booking gate keeps its
appointments.view fallback so a secretary who may book is not blocked by a
resource-config permission.

Defaults were picked to preserve today's effective access, so no role gains or
loses a page from this move.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 18:11:05 +03:30
hamedandClaude Opus 5 103d913cd0 refactor(admin): restructure the new-appointment modal around its real steps
The booking modal presented one flat scroll of fields whose order did not
match the order of the decisions behind them, and gave no reason when the
submit button stayed grey.

- Group the form into numbered steps (service+time, patient) so the order of
  decisions is visible. The optional visit-price collapse stays unnumbered —
  numbering an optional step reads as required.
- Show the first blocking condition above the footer instead of leaving a
  disabled button unexplained.
- Label the header chip's facts ("device:", "supervising doctor:") and add the
  appointment's Jalali date, which the modal never displayed at all.
- Replace the hand-rolled primary/ghost button pair with the design system's
  `.seg` + `.on`, and announce state via aria-pressed.
- Move autoFocus off the patient search in picker mode; the first decision is
  the section select above it.
- Give every input an id and its label an htmlFor.
- Surface a distinct error state for the slot query. A failed request used to
  fall through to "not enough free time", which sent users to another day for
  no reason.
- Raise the service remove button (18px), the duration pill and the time chips
  to at least the 32px hit target; mark service rows role=checkbox.
- Modal close button gets an accessible name; `.field` controls stretch to the
  full 40px box so the whole frame is clickable.

Runtime probe on the open modal goes from 4 unnamed icon controls, 1 unlabelled
field and 2 sub-32px controls to clean, across light/dark/compact/mobile.

The redesign-page probe now names the offending elements instead of only
counting them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 12:08:25 +03:30
hamedandClaude Opus 5 d8aabe5d0a feat(admin): treatment plan tab, staff session screens and the device form editor
Three screens, each reusing what already exists rather than inventing a parallel
look. The treatment plan lives as a tab on the service page next to categories,
because the course belongs to the service; the switch is the protocol's existence
rather than a separate boolean that could disagree with the step list. Each step
asks for days since the previous session, which is how the interval actually
works and what the form should therefore say.

The staff screens are the flow from the reference screenshots: today's sessions,
then a session where each area is started, recorded and closed on its own. Field
inputs are built from the schema the server sends per resource type, so a clinic
adding an RF device sees its own form here without a code change.

StatusBadge gains treatment session and area states rather than a second badge
component sitting beside it, and the resource type modal grows a field editor so
the operator form is configured where the device is defined.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 18:29:49 +03:30
hamed 0e7970d6e0 feat: replace checkboxes with Switch component for better UI consistency
- Updated DoctorDetailPage, MySecretariesPage, RecordNumberSettingsPage, RepresentationsPage, ResourcePoolsPage, ResourceTypesPage, SecretariesPage, SecretaryDetailPage, SettingsPage, SkillsPage, SmsWalletPage, and TagsSettingsPage to use the new Switch component instead of native checkboxes.
- Enhanced accessibility by ensuring the Switch component uses appropriate roles and labels.
- Added tests for the new Switch component to ensure functionality and accessibility compliance.
- Updated styles to accommodate the new Switch component design.
2026-08-05 16:09:46 +03:30
hamedandClaude Opus 5 f06efe26c0 fix(holidays): honest dates and reachable fields on the holidays page
The table had two date columns for one date: "تاریخ" printed the raw
1405-05-13 string in Latin digits, and the column labelled "میلادی" ran the
same day through formatDate — which returns Jalali. One date, twice, under a
label that lied. It is now a single formatted Jalali column.

The closure form used a native <input type="date">: Gregorian, an English
mm/dd/yyyy placeholder in an RTL Persian panel, and a white box in dark mode
because a native control does not follow the theme. It is the shared Persian
picker now.

That picker turned out to be a div with an onClick — no role, no tab stop, no
accessible name, and its clear button was a span. Since every page that picks
a date goes through it, it gained role/tabIndex/Enter-Space, an ariaLabel
prop, and a real button for clear. The page passes labels for the year select
and both form fields, and the global topbar search got an aria-label, which
takes the runtime accessibility probe on this page to clean.

useHolidays now returns an error, so a failed request reads as an error
instead of an empty year — previously indistinguishable.

The page had no test file; it has eight.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 17:25:56 +03:30
hamed e0e8fbd1e4 feat: implement BackButton component for consistent navigation
- Added BackButton component to standardize back navigation across pages.
- Integrated BackButton into various pages, replacing custom back buttons for consistency.
- Updated PageHeader to accept backTo prop for displaying BackButton when navigating from subpages.
- Created useGoBack hook to handle navigation logic, determining whether to go back in history or redirect to a fallback page.
- Added tests for BackButton and its integration with PageHeader to ensure expected behavior.
2026-07-29 20:26:51 +03:30
hamed b423a0ae4d refactor: normalize date handling to Tehran timezone
- Updated date handling in BlogSeoFields and ScheduleSection to use Tehran timezone utilities for consistency.
- Introduced `toTehranClockTime`, `tehranWallClockToUnix`, and `todayIso` functions for accurate date representation.
- Modified various components to utilize these new utilities, ensuring that date strings are correctly formatted and timestamps are accurately converted.
- Enhanced API documentation to clarify the handling of date fields, emphasizing the importance of server-local midnight.
- Added tests to verify that date overrides and holidays maintain the correct day without shifting due to timezone discrepancies.
2026-07-27 19:37:44 +03:30
hamed 55ab2f5dfc Implement comprehensive dark/light mode overhaul for admin panel
- 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.
2026-07-27 16:41:52 +03:30
hamedandClaude Opus 4.8 f33c7a3eab feat(clinic-doctor): full permission coverage + enforcement, parity with secretary
The clinic-member-doctor permission system (ClinicDoctorPermission) lagged the
secretary system: only 6 resources, enforced in ~6 places, dead toggles
(services.update never checked), and a sidebar showing just appointments+patients.
Bring it to parity so a clinic owner can control exactly what each member doctor
does — while an independent doctor stays completely unrestricted.

Coverage: add insurances, addresses, inventory, tags, staff, discounts, sms to
ClinicDoctorPermission::DEFAULT_PERMISSIONS + DoctorPermissionsModal
(subscription/clinic_doctors stay owner-only by design).

New App\Clinic\Security\ClinicDoctorAccessChecker (parallel to
SecretaryAccessChecker):
- denyUnlessGranted(user, resource, action): 403 only for a clinic-member doctor
  in the clinic context; owner/admin/secretary/independent-doctor pass through.
- memberClinicId(user): resolves the member doctor to the CLINIC's tenant so the
  role-based controllers (Inventory/Tag/Staff/Discount/Sms) stop showing them
  their personal tenant in clinic context.

Enforcement wired into 10 controllers alongside the existing secretary gates:
ClinicService (services), Insurance (insurances), Patient (patients+payments),
Staff, Discount, Inventory, Tag, SmsWallet, Payment, PaymentMethod.

Frontend: the guest-doctor sidebar branch now exposes every permitted resource
(gated by can()) plus a «تنظیمات» entry; both settings navs (PurchaseSubscription
Sidebar + SETTINGS_MENU) are now permission-filtered for a scope=clinic doctor,
not just secretaries; my-payments route gets the missing payments permission.
CRUD-button gating already applies (usePermissions is role-agnostic).

Tests: ClinicDoctorPermissionEnforcementTest (member denied/allowed +
independent-doctor-unrestricted); guest-doctor sidebar gating. Backend 375 pass,
frontend 503 pass. docs/api/clinic.md updated with the full resource set +
enforcement notes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 19:09:16 +03:30
hamed 74577c2ff6 feat: unify doctor title handling and enhance specialty selection
- Implemented a helper function `displayDoctorName` to prepend "دکتر" to doctor names for consistent display across the application.
- Updated various components (InviteDoctorModal, DashboardPage, DoctorDetailPage, DoctorsPage, etc.) to utilize the new helper for rendering doctor names.
- Modified the DoctorFormPage to automatically add the "دکتر" title in the UI without requiring user input.
- Fixed the EditSpecialtyPicker component to allow multiple specialty selections, resolving a UI bug where only one specialty could be selected at a time.
- Ensured that the backend strips the "دکتر" title from the name during pre-registration and doctor creation processes.
- Added tests for the new functionality, including checks for title handling and specialty selection logic.
- Updated API documentation to reflect changes in name handling and display logic.
2026-07-19 19:57:03 +03:30
hamed 7761c37a3e feat: update user roles and passwords in QA driver, enhance documentation with error codes, and improve trial activation error handling 2026-07-19 15:19:03 +03:30
hamed 773f9d4d16 feat: update session payment logic to ensure accurate payable amounts and reflect consumables in cost breakdown
- 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.
2026-07-19 13:29:46 +03:30
hamed 357adb1d14 feat: enhance payment status handling and summary in MyPaymentsPage
- Added support for 'partial' payment status in MyPaymentsPage and related components.
- Updated API responses to include 'paid_rials' and 'summary' for invoices.
- Introduced InvoicePaymentStatus service to derive payment status based on actual payments.
- Enhanced tests to cover new payment scenarios including partial payments and payment methods.
- Updated documentation to reflect changes in payment status and API responses.
2026-07-19 10:38:29 +03:30
hamed 5c8fe8ece4 feat: add payments summary endpoint and UI redesign for MyPaymentsPage
- Implemented a new API endpoint `/api/v1/my/billing/payments/summary` to provide a financial summary of payments with filters for national code, status, and date range.
- Updated the InvoiceRepository to aggregate totals for paid and unsettled invoices.
- Created a new hook `usePaymentsSummary` to fetch summary data in the frontend.
- Redesigned the MyPaymentsPage to align with the ClaimsPage structure, incorporating a design system, summary statistics, and improved filtering options.
- Added tests for the new payments summary endpoint to ensure correct functionality and filtering behavior.
2026-07-19 10:12:01 +03:30
hamed 20bdc49e89 feat(claims): add tracking number and status history for claims
- Introduced `tracking_number` field in the `claims` table to store the insurance tracking number.
- Created `claim_status_logs` table to maintain a history of status changes for claims, including who made the change and when.
- Implemented `ClaimStatusLog` entity and repository for managing status log entries.
- Updated `ClaimService` to log transitions and handle tracking numbers during claim submissions.
- Added new API endpoint for fetching claims by patient, including detailed claim history and status logs.
- Enhanced frontend with a new `ClaimPatientDetailPage` to display claims and their status history.
- Added tests to ensure correct aggregation of claims and proper handling of status transitions.
2026-07-18 23:38:02 +03:30
hamedandClaude Opus 4.8 7921407f33 feat(appointments,patients): make clinic context a first-class citizen
Three related fixes, all rooted in the same flaw: authorization and scoping
decided by the caller's role instead of by the environment the data belongs to.

1. Single-appointment access (clinic operations were entirely broken)

AppointmentController::canView/canManage only knew the patient, the owning
doctor and admin -- appointment.clinic was never consulted. A clinic user could
create an appointment through /my/appointment but got 403 on detail, edit,
move, reserve transfer/replace and status change, so nearly every appointment
operation failed in clinic mode.

AppointmentAccessChecker now decides from appointment.clinic: clinic owner,
member doctor (via ClinicDoctorPermissionChecker) and assigned secretary (via
active context + DoctorSecretary) are recognised. Actions reuse the existing
permission vocabulary, so active=false remains the single source of truth for
"collaboration ended". Cancellation is gated separately and an inline status on
PATCH /appointment/{uuid} cannot bypass that gate. The patient is narrowed to
view + cancel.

Also fixed alongside: listByDoctor now serves a clinic manager but scoped to
that clinic; todayStats gained an admin branch and no longer passes an array of
doctor ids as the clinic parameter; PatientController::appointments filters on
appointment.clinic instead of current membership, so deactivating a doctor no
longer erases clinic appointment history from the case file.

The doctor-only active_slot_key was reviewed and deliberately left alone -- a
doctor is one physical person, so adding clinic to the key would permit
double-booking, not fix a bug. Reasoning recorded on the entity.

2. Appointment registration and confirmation

Panel-created appointments are born pending ("ثبت شده") instead of confirmed.
Confirming is now an explicit act: POST /appointment/{uuid}/confirm transitions
the status, files the case file for the appointment's environment (reusing an
existing record or creating one) and registers full or partial payments on the
resulting visit -- all in one transaction.

AppointmentExpiryService would have expired those pending appointments the
moment their slot time passed; findExpiredPending is now limited to online
gateway holds, which are the only pendings carrying a TTL. A pending
appointment still occupies its slot, so the time stays reserved.

The admin panel gets a "قطعی کردن نوبت" modal showing the visit fee, each
selected service, the total, and paid/remaining/status. It is wired inside
AppointmentStatusDropdown, so picking "confirmed" anywhere (timeline, detail,
reserve list, info modal) goes through it and confirmation can never silently
skip the case file and payment.

3. Clinic case-file access

PatientRecordScopeResolver replaces the single-destination role mapping: the
active context decides, so a doctor invited into a clinic finally sees their
patients' records there. A clinic record is per-patient and shared by design,
so "their own patients" is derived from appointments with that doctor in that
clinic rather than from a new column. Clinic secretaries are limited to their
assigned doctors. Read and write share one rule, and out-of-scope records
report 404 so other environments are never disclosed.

Tests: 29 new cases across the three areas (clinic appointment access, confirm
flow, clinic record access). Full suite 466 tests, 2 pre-existing failures
unchanged. API docs updated for all three.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 21:04:50 +03:30
hamed 42d9ad26c5 Add tests and implementation for ServiceDetailPage and PriceInput components
- Implement PriceInput component tests to validate Persian and Arabic numeral handling, input formatting, and controlled behavior.
- Create ServiceDetailPage component with detailed service information, including pricing, insurance coverage, and editing capabilities.
- Add API tests for service item detail retrieval and coverage synchronization with insurance contracts.
- Ensure proper error handling and user feedback for service item retrieval and coverage management.
2026-07-18 12:10:49 +03:30
hamed e4ddd38f0c feat: add per-doctor permissions management in clinics
- Implement DoctorPermissionsModal for managing doctor permissions in clinics.
- Create usePermissions hook to handle user permissions context.
- Add migration for clinic_doctor_permissions table with default permissions.
- Develop ClinicDoctorPermissionController for handling permissions API.
- Create ClinicDoctorPermission entity to manage permissions data.
- Implement ClinicDoctorPermissionRepository for database interactions.
- Add ClinicDoctorPermissionChecker for permission validation logic.
- Write tests for clinic doctor permissions functionality.
2026-07-18 09:44:13 +03:30
hamedandClaude Fable 5 ee69ac96be feat(admin): comma-grouped Latin amounts on the session payment step
Add an opt-in latin prop to PriceInput (en-US grouping, English digits) and
use it for the discount-value and payment-amount fields on PaymentStep, which
were raw number inputs. Amounts now show 3-digit comma grouping and Persian
digits typed are converted to English (via PriceInput's toEnglishDigits).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 12:45:45 +03:30
hamedandClaude Fable 5 204c7debe1 fix(discount): correct edit-form data + calendar clipping + input styling
- List endpoint returned camelCase keys (getArrayResult) so the edit modal
  read empty discount_type/target_*; return toArray() (snake_case) instead.
- Portal the Persian date-picker calendar to body (fixed) so it no longer
  renders under the modal's overflow-scroll body.
- Style the PriceInput/number fields with cp-input in the rule modal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 12:37:43 +03:30
hamedandClaude Fable 5 49b2ca60d7 feat(appointment): log cancellation events and show them in a Timeline
Introduce the first per-appointment event system. On cancel (via the status
or general update endpoints) an AppointmentEvent (type=cancelled, «نوبت لغو
شد») is recorded with the actor, cancel time, and an optional cancel_reason,
plus a warning-level app_log entry. New GET /appointment/{uuid}/events
returns the ordered event list. The admin appointment detail page renders a
Timeline section and the cancel dialog now collects an optional reason.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 11:13:23 +03:30
hamedandClaude Fable 5 15f1c8d1eb feat(admin): force Latin digits in numeric fields globally
- Add a numeric prop to the base Input component that sets inputMode,
  dir=ltr, lang=en and normalizes Persian/Arabic digits to Latin via the
  shared toEnglishDigits on every change.
- Dedupe digit conversion: PriceInput now uses toEnglishDigits instead of
  its local map; AppointmentsPage mobile handler uses sanitizeMobileInput.
- Fix raw national-code / mobile inputs in NewAppointmentModal and
  NewAppointmentDrawer that stripped Persian digits without converting.
- Cover the numeric Input behaviour with unit tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 10:58:55 +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
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 7b8a5c2775 feat(date-input): refactor PersianDateInput to use PersianDatePicker for Jalali calendar support 2026-07-16 08:26:39 +03:30
hamedandClaude Fable 5 27765b33d2 test(ui): update StatusBadge expectation to the new design label (قطعی شده)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 23:49:04 +03:30
hamedandClaude Fable 5 7354c92e40 feat(appointments): row actions menu + info/move/transfer/replace modals — phase B
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>
2026-07-13 23:47:54 +03:30
hamedandClaude Opus 4.8 580bc983b3 feat(patient): complete "اطلاعات پرونده" demographic form
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>
2026-07-13 11:51:18 +03:30
hamed 2cfc516e2c fix(altcha): update attribute from challengeurl to challenge in Altcha component and home template 2026-07-10 12:06:03 +03:30
hamed 3eee6c3886 Update community IDs, enhance CaptchaController caching, and modify home template for Altcha integration
- Changed community IDs for various components in graph.json to reflect updated associations.
- Added Cache-Control headers to the challenge and config methods in CaptchaController to prevent caching by CDNs and proxies.
- Updated the Altcha widget in home.html.twig to include a language attribute for better localization.
- Added a new AST cache file for CaptchaController to improve performance.
- Updated manifest.json with new modification times and AST hashes for several files.
2026-07-10 11:57:16 +03:30
hamed c3c520801d feat(captcha): add ALTCHA configuration endpoint and integrate into HomeController
- Introduced a new endpoint `/api/v1/altcha/config` in CaptchaController to return the status of the ALTCHA captcha.
- Updated HomeController to inject AltchaService and pass the captcha status to the home page template.
- Modified the home.html.twig template to conditionally render the ALTCHA widget based on the captcha status.
- Updated manifest.json and cache files to reflect changes in the codebase.
2026-07-10 11:18:40 +03:30
hamed 8b6d431f61 feat(auth): integrate Captcha validation in PasswordAuthenticator
- Added CaptchaGuard dependency to PasswordAuthenticator.
- Implemented Captcha validation in the authenticate method to enhance security.
- Updated the login modal in home.html.twig to redirect to the admin panel instead of opening a modal.
- Enhanced the Altcha widget with localized strings for better user experience.
- Removed the login modal implementation from home.html.twig to streamline the login process.
- Updated manifest.json and AST cache files to reflect changes in the codebase.
2026-07-10 11:05:59 +03:30
hamed 10b0743d9a Implement ALTCHA captcha service with challenge generation and solution verification
- Added AltchaService class for managing ALTCHA captcha challenges and solutions.
- Created CaptchaController to handle API requests for generating challenges.
- Introduced CaptchaGuard for validating captcha solutions on public endpoints.
- Developed unit tests for AltchaService to ensure challenge creation and solution verification functionality.
- Implemented integration tests for the Captcha API endpoint and captcha bypass behavior when disabled.
- Added documentation for the Captcha API in the corresponding markdown file.
2026-07-10 10:31:59 +03:30
hamed f3ca6d844f feat: implement Portal component and refactor modals to use it for improved positioning 2026-07-04 22:05:27 +03:30
hamed 02c34bac8e fix(modal): render Modal with React Portal to center it on the screen
fix(calendar): add type="button" to all buttons in PersianCalendar to prevent form submission
2026-07-02 11:48:34 +03:30
hamed cc193c866b Add manifest.json for graphify-out documentation with metadata for various files 2026-06-30 22:12:26 +03:30
hamed 6084dc5d6b feat: add comprehensive tests for UI components, hooks, and API interactions
- Implement tests for Pagination, StatusBadge, ConfirmDialog, and MobileInput components.
- Add tests for useSubscription, usePaymentConfig, and usePwaInstall hooks.
- Create tests for API requests in the api module, including success and error handling.
- Add utility function tests for formatting and validating Iranian mobile numbers.
- Implement tests for BlogFormPage and BlogsPage to validate form submissions and data fetching.
- Add tests for LoginPage to ensure proper validation and state management.
- Create tests for authStore and uiStore to validate state management and functionality.
- Set up Vitest configuration and testing utilities for consistent testing environment.
2026-06-28 22:58:15 +03:30
hamed 1997b78d11 feat(calendar): add year picker functionality to PersianDatePicker and PersianCalendar 2026-06-25 20:00:13 +03:30
hamed 3eb82ffa7d feat(claims): replace PersianDateInput with PersianDatePicker and add quick date range buttons 2026-06-24 06:24:22 +03:30
hamed 27840da78d feat: integrate insurance coverage management for clinic services
- Updated NewSessionPage to calculate patient share based on insurance coverage rules.
- Refactored billing calculations to utilize new patientShareOf function for service items.
- Enhanced API documentation to reflect changes in service coverage structure.
- Implemented ServiceInsuranceModal for managing insurance coverage per service.
- Added UI components for displaying and editing insurance coverage details.
- Removed obsolete toggle switch styles and adjusted CSS for new components.
- Ensured backend endpoints support both service_item_id and service_item_uuid for flexibility.
2026-06-24 04:23:50 +03:30
hamedandClaude Opus 4.8 0bd18d74b7 feat(ui-kit): design tokens + StatCard + button variants (foundation)
Add accent (orange) + pastel stat-card tokens (light/dark), button
accent/outline/lg/block variants, and a pastel StatCard primitive,
aligning the admin design system with the clinic-pro-tauri reference.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 17:34:34 +03:30
hamed da57c554c1 feat: implement MobileInput component for standardized mobile number input and update related forms to use it 2026-06-19 15:28:40 +03:30
hamed 9b0af282e0 feat(payment): update payment status values to use 'success' and 'failed' instead of 'received' and add new status 2026-06-19 01:21:57 +03:30
hamed fa6656df48 feat(subscription): implement feature gating for subscription-based access in admin panel 2026-06-15 12:00:36 +03:30
hamed 5cdcec23a9 feat: enhance staff management and payment gateway features
- Fix national code handling in staff creation and updates to support Persian digits.
- Update ClinicStaff entity to allow longer national codes (up to 15 characters).
- Implement support for clinic secretaries in SecretaryController, allowing creation without a doctor UUID.
- Add a new endpoint to retrieve doctors associated with a clinic for secretary management.
- Improve appointment management by ensuring doctors are selectable even when no appointments exist.
- Extend PatientController to allow secretaries to create patient records if they have the appropriate permissions.
- Introduce a PriceInput component for better price formatting in forms, supporting Persian digits.
- Add a MockGateway for testing payment processes without real transactions.
- Enhance SMS settings management with an approval flow for post-visit text messages, including new fields for pending text and status.
- Update migrations to reflect changes in database schema for national codes and SMS settings.
2026-06-15 11:03:56 +03:30