components/appointment/ had every colour hard-coded, so the flow rendered
identically in either theme even after the wiring was fixed. It now reads from
CSS custom properties.
These are not new colours. The :root values are byte-for-byte the hex codes
that were already in the components — twenty-one files, mapped one to one — so
light mode is unchanged. The dark values are derived from those same colours:
surfaces and borders darkened, text inverted, and the two brand colours (the
indigo and the orange) lightened rather than replaced, because both lose
contrast against a dark surface at their original values.
Verified in a headless browser with prefers-color-scheme forced dark:
data-theme lands on <html> and --ap-surface resolves to #1b1b20 rather than
white. Six one-off colours remain hard-coded — a success green, an error red
and similar — each used exactly once and none of them a surface.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A doctor now has one booking schedule per context — the personal practice plus
one per clinic — and every booking endpoint takes an optional clinic_uuid where
omitting it means the personal practice, not a wildcard. This site sent none, so
a clinic-only doctor showed no availability at all and a doctor working in both
places silently booked into the wrong one.
- services/response.js: getBookingLocations + clinic_uuid on slots,
service-slots, booking-services and month-availability. The manual query
building is kept so the service_item_uuids[] serialisation does not change.
- AppointmentPage owns the selected location; booking_mode and services are
derived from it instead of a separate getBookingServices call, which drops a
request. Changing location clears the selected service, slot and date, since
a service from one location cannot be booked into another.
- New LocationSelect step, shown only when there is more than one location.
The list arrives sorted by earliest free slot, so the first item is the
default and is not re-sorted here.
- DatePicker drops its month cache when the location changes; otherwise the
previous location's disabled days stayed on the calendar.
- The slot address now comes from the selected location rather than
doctor.address, which does not contain clinic addresses.
- clinic_uuid rides through to the appointment payload, and
/appointment/[doctorId]?clinic_uuid=… preselects a location.
- Doctor page JSON-LD gains availableService from the bookable services.
openingHoursSpecification still needs a public weekly-hours endpoint.
Removed the dead locateVisit state, which was initialised true and never unset.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the mock for-another button with a real toggle: switching keeps
the user's own data, clears the form to editable patient fields (phone
becomes an input, adds علت مراجعه), and can switch back. SubmitData now
sends for_self plus patient_* only when booking for someone else, skips
the self-profile PATCH/POST in that case, stores the booking expires_at,
and surfaces a clearer 409 message. Thread appointmentExpiresAt through
the wizard to the payment step.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GET /api/v1/insurances returns success(['data' => items]) → the body is
{ data: { data: [...] } }, so after the interceptor unwraps once the
array lives at res.data.data, not res.data. The callers set the list to
the wrapper object, so insurance.find threw 'not a function'. Read
res.data.data and guard with Array.isArray in both the booking detail
form and the dashboard insurance loader.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>