- Persist selected date across month navigation using module-level vars;
datesSet re-applies is-selected and restores slots when returning
- Show "No availability this month" overlay after a fetch returns empty;
gated on initializedRef+fetchedRef so auto-advance phase is silent
- Fix Dec 31 overflow: showNonCurrentDates:false hides adjacent-month days
- Fix fc-day-disabled background tint in calendar.css
- Gate auto-advance on loading() callback so removeAllEventSources()
spurious eventsSet() fires don't trigger premature month jumping
- Inline overlay styles to avoid Tailwind cascade uncertainty; document
the module-level CX constant pattern as the general fix
- firstName added to booking form; storeSlot sends email directly when
full contact info present, skipping tempstore redirect
- Remove BookingForm.php and /schedule/book route (replaced by inline form)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New pure-vanilla progressive formatter that turns typed digits into
(123) 456-7890 (or 1 (800) 555-1212 for +1 numbers) on the fly.
- Works for free-form input: typing, pasting, editing anywhere, backspacing,
extra chars, etc. — no hard mask or input restrictions.
- Applied to:
- The Preact <rpt-booking> widget phone field (home page quick booking + details).
- The final Drupal confirmation form at /schedule/book (via lightweight
enhancer + .rpt-phone class).
- Prefills last_name / phone / comments on the confirmation form when the
widget was used to pick the slot (so collected phone isn't lost).
- No new dependencies whatsoever:
* Zero npm / package.json / composer changes.
* Zero additional CDN / external scripts (uses native String.replace,
regex, and input event + selection APIs only).
* The new js/phone-format.js is simply attached via the pre-existing
'app' library (already loaded on all riverside_pt.* routes).
* Formatter logic duplicated in the ESM component (tiny pure function).
- The two other modified files (calendar.css, calendar.js) were left
uncommitted as they are unrelated to this feature.
- Remove client-side serviceEarliestDate; instead auto-advance month by
month until the server returns events (capped at 12 months)
- Only mark initialized when a date is actually found, so empty months
don't block auto-select on subsequent fetches
- Add per-service fault injection flags in ScheduleController::events
to force zero availability for testing the no-slots UI path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Merge rpt-appt-type + calendar into unified rpt-booking Preact component;
service state drives event source via useEffect, no DOM event bus
- Each service has distinct availability (different slot density, start hours);
surgical rehab only available 46+ days out
- Slot click reveals inline Last name / Phone / Comments form; submits all
fields together to storeSlot rather than redirecting immediately
- Fix nextBusinessDay() timezone bug (toISOString is UTC; use local date
components instead); pre-select first available day >= next business day
- Today always has no availability (backend now starts from tomorrow)
- Replace all raw hex colour values with named palette tokens throughout
templates and JS components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Slots panel moves from popup to side-by-side with the calendar
- First available slot is pre-selected (highlighted) on load
- Calendar initializes to the next business day
- eventsSet auto-selects that date if it has availability
- Events endpoint now skips Sat/Sun (N > 5)
- Removed backdrop/close-button popup infrastructure
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resize handler uses functional setLeft (no direct left read).
onPointerDown uses left from render closure directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Snap clamps after rounding so it can't overshoot max on narrow viewports
- atEnd computed inline each render from live measureMax()
- forceUpdate on resize guarantees re-render even when left doesn't change
- Track gets explicit width (TOTAL_W) so gap areas are hit-testable
- Resize handler always calls setLeft (clamp or no-op) to keep state consistent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drop live drag tracking, rubber-band resistance, and dragging ref.
A swipe > 50px left/right calls next()/prev() — same result, far less code.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Live drag tracks the finger with transition disabled; slight rubber-band
resistance at both edges. On touchend, snaps to the nearest card
boundary within [−maxLeft, 0].
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Register resize listener once with empty deps; track left via ref so
the debounced callback always reads the current offset without
re-registering on every click.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- rpt-testimonials: pixel-offset carousel with DOM-measured max scroll,
cards overflow the 1200px safe area to the right; red debug border on container
- calendar: circle-per-day design replacing event bars; teal outline for
available days, filled for selected; dateClick replaces moreLinkClick
- settings.php: normalize BASE_URL before parse_url to fix trusted host
error when scheme is missing; always include localhost fallback patterns
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>