Commit graph

64 commits

Author SHA1 Message Date
Philip Peterson
0196733be8 scroll 2026-06-08 19:14:22 -07:00
Philip Peterson
32c6b6dd5a add flood control 2026-06-06 00:17:08 -07:00
Philip Peterson
871ac5b3ef fix 2026-06-06 00:13:21 -07:00
Philip Peterson
d4300cf04e Consolidate classes 2026-06-05 02:01:03 -07:00
Philip Peterson
8d099b220f Fixes 2026-06-05 01:54:26 -07:00
Philip Peterson
27e2b6f2d9 have Drupal forward logs to actual logs 2026-06-04 23:22:43 -07:00
Philip Peterson
bb84ca34a8 fixes 2026-06-04 22:52:41 -07:00
Philip Peterson
39ced1a5af Fixes 2026-06-04 00:15:22 -07:00
Philip Peterson
9bbb7712fe Fix FAQ 2026-06-04 00:13:32 -07:00
Philip Peterson
8a96b526f1 Slugs 2026-06-04 00:10:57 -07:00
Philip Peterson
1e3ba132a4 Suppress duplicate key errors on semaphore table during rebuilds
- In _riverside_pt_rebuild(): proactively TRUNCATE the semaphore table
  at the very start of every rebuild. This eliminates the common
  'duplicate key value violates unique constraint "semaphore____pkey"'
  errors for 'state:Drupal\Core\Cache\CacheCollector' and 'cron' that
  appear in postgres logs.

- In entrypoint.sh: add TRUNCATE semaphore at strategic points
  (right after site:install, before module enables, before/after
  riverside:rebuild, before final drush cr). Wrapped with || true
  so they never break the startup script.

- Added a note in CLAUDE.md under the rebuild section explaining
  the errors and the quick manual fix.

These are harmless (Drupal's DbLockBackend usually recovers) but
very noisy in the container logs during the default full rebuild
path.
2026-06-04 00:06:27 -07:00
Philip Peterson
4d895d1b0d Use page routing 2026-06-04 00:05:52 -07:00
Philip Peterson
60ecacb4d4 Fix scrolling 2026-06-04 00:02:27 -07:00
Philip Peterson
797e580cc0 Create custom /contact page with details and appointment CTAs
- Refactor AboutController to PageController to handle multiple static pages:
  - /about
  - /services/{slug} (diagnostic, sports, pre-post, neuro)
  - /contact (new)

- New template riverside-pt-contact.html.twig:
  - Contact details (address, phone, email)
  - Office hours
  - 'Send us a message' section directing to booking tool
  - Multiple 'Make an Appointment' links back to /home#book-an-appointment

- Updated riverside_pt.routing.yml with riverside_pt.contact route
- Registered 'riverside_pt_contact' theme in riverside_pt.module
- Updated riverside_pt.install to skip legacy node creation for 'Contact' (and previously About/Services) to avoid alias conflicts
- Minor updates to home template, header handling, libraries (scroll support), and other controllers for consistency with page flows and email/booking features

All details pages (/about, /services/*, /contact) now include clear links back to 'Make an Appointment'.
2026-06-03 23:55:02 -07:00
Philip Peterson
95a0a3e004 Use labels 2026-06-03 23:33:09 -07:00
Philip Peterson
6879b056da Use sendmail only on dev 2026-06-03 23:30:44 -07:00
Philip Peterson
96eafc4f5c Dont autoselect service type 2026-06-03 23:16:40 -07:00
Philip Peterson
26537efa94 Fix CSS 2026-06-03 23:08:02 -07:00
Philip Peterson
2dd6c7da22 Add email field to booking form + dev mail mocking
- Add required email input (with autocomplete="email") to the booking
  details form in the homepage Preact widget (rpt-booking.js).
  Update EMPTY_FORM, submit payload, confirmedAppointment, and success
  summary to include it. The form now collects: first/last name, email,
  phone, comments.

- Update ScheduleController::storeSlot to extract/pass email in the
  booking_request mail params (and require it for the full-contact path).
  Log failures with details; return a structured error with a user-friendly
  message instead of bare "mail_failed".

- riverside_pt_mail hook now includes the user's email in the notification
  body (when provided).

- Dev improvements for mail:
  - In DEBUG mode (default on localhost), force php_mail interface in
    settings.php so the mailer uses the sendmail_path override.
  - Dockerfile + entrypoint.sh now provide/install a fake-sendmail.sh
    that prints the full email (To, Subject, headers, body from the
    hook) to stderr (visible in `docker compose logs`) and always
    succeeds (exit 0). This prevents "sh: 1: /usr/sbin/sendmail: not
    found" and guarantees booking submissions never return the
    "unable to send confirmation email" error in dev.
  - In non-DEBUG, still uses symfony_mailer + Postmark as before.
  - The fake is also baked into the image for consistency.

- JS error handling now prefers the server-provided 'message' from
  the JSON error response (better UX for real mail failures).

- Update CLAUDE.md with the new email field + dev mail mocking behavior.

- New file: docker/php/fake-sendmail.sh (the mock).

This addresses the recent "mail_failed" issues while keeping production
email via Postmark.
2026-06-03 23:05:06 -07:00
Philip Peterson
5293f3f347 Fixes to calendar lifecycle 2026-06-03 22:47:31 -07:00
Philip Peterson
59b7e57b5e Remount for service 2026-06-03 22:36:45 -07:00
Philip Peterson
f882149a37 Fix for race condition 2026-06-03 22:21:43 -07:00
Philip Peterson
8962fc5f0e Smooth scroll, booking refactor, success summary
- Add scroll.js: data-scroll-to attribute drives smooth scrollIntoView;
  scroll-margin-top at md+ accounts for fixed header offset
- Wire Services, FAQ, Book An Appointment, View Our Services nav/hero
  links to on-page anchors; don't close hamburger on scroll-link clicks
- Refactor booking calendar: own the fetch (useEffect + dateRange state)
  instead of handing URL to FullCalendar; removes fetchedRef complexity;
  noSlotsInMonth derived cleanly from fetchLoading + fetchedEvents
- Success state shows appointment summary (name, service, date/time);
  hides calendar/form on success; no "book another" button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 22:14:39 -07:00
Philip Peterson
9e1e6a57b7 Hoist Tailwind classes to CX object; fix no-slots overlay flash
- Move all Tailwind class strings to a module-level CX constant so the
  JIT scanner sees complete literals in one place rather than scattered
  across template expressions
- Convert no-slots overlay and wrapper from inline styles to CX entries
  (adds z-10 to fix stacking above FullCalendar grid)
- Fix no-availability message flashing on month navigation: reset
  fetchedRef in datesSet so eventsSet ignores stale pre-fetch firings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 21:20:04 -07:00
Philip Peterson
1b7577fa17 Calendar polish: selection persistence, no-slots overlay, various fixes
- 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>
2026-06-03 20:51:43 -07:00
Philip Peterson
e3c2e3e3a1 Add nice non-restrictive phone number input formatting for booking
- 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.
2026-06-03 20:35:40 -07:00
Philip Peterson
58988a4fe8 Fix calendar auto-advance and add fault injection for availability
- 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>
2026-06-03 19:52:14 -07:00
Philip Peterson
b000b824ed Service-aware booking: selector drives calendar, inline request form
- 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>
2026-06-03 19:39:35 -07:00
Philip Peterson
2f624f73ba Fix colors 2026-06-03 19:12:53 -07:00
Philip Peterson
e9bce5aac8 Fix dragging issues 2026-06-03 02:31:16 -07:00
Philip Peterson
50f14afcd1 Appointment type selector 2026-06-03 02:13:06 -07:00
Philip Peterson
c073984e82 Redesign booking calendar: inline slots, M-F only, pre-select next day
- 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>
2026-06-03 02:02:56 -07:00
Philip Peterson
b7287e8076 Clean up carousel: remove debug border, drop unused wrapRef
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 01:56:07 -07:00
Philip Peterson
d56e94ad09 Remove leftRef now that forceUpdate made it redundant
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>
2026-06-03 01:54:48 -07:00
Philip Peterson
bccac386a7 Fix carousel: swipe snap, disabled state, pointer events, resize
- 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>
2026-06-03 01:54:29 -07:00
Philip Peterson
d693e87e02 Simplify swipe: direction-detect on touchend only
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>
2026-06-03 01:41:13 -07:00
Philip Peterson
52af78a31a Add touch/swipe support to testimonials carousel
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>
2026-06-03 01:40:45 -07:00
Philip Peterson
b41113f318 Fix resize handler: use ref to avoid stale closure and listener churn
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>
2026-06-03 01:40:15 -07:00
Philip Peterson
b0eaca462f Add testimonials carousel, redesign calendar, fix trusted host
- 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>
2026-06-03 01:37:13 -07:00
Philip Peterson
0d35dda628 Fix palette swatches, login styling, and login redirect
- PaletteController: render proper color swatch cards (box + label) and
  wrap output in Markup::create() so Drupal's XSS filter doesn't strip
  inline style attributes
- riverside_pt.module: scope page_attachments and page_top to
  riverside_pt.* routes only — Tailwind preflight was blowing away
  Drupal's default form styles on the login page
- settings.php: derive trusted_host_patterns from BASE_URL so the host
  and port always agree; prevents localhost:8080 being treated as untrusted
- entrypoint.sh: pass --base-url to drush site:install so Drupal stores
  the correct canonical URL from the start

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 03:00:19 -07:00
Philip Peterson
1cb8335158 add swatch page, rename colors 2026-06-01 02:46:47 -07:00
Philip Peterson
21d4174c8f wip 2026-06-01 02:21:51 -07:00
Philip Peterson
1d9b1c1625 functionality build out 2026-06-01 01:47:26 -07:00
Philip Peterson
8c5ce93d79 Fix statelessness 2026-05-28 18:14:59 -07:00
Philip Peterson
d98f9a9efd Fixes 2026-05-28 00:07:02 -07:00
Philip Peterson
91b6b3af89 Fix styling 2026-05-27 23:42:59 -07:00
Philip Peterson
ba4b140d94 Adjust breakpoints to standard sm/md/lg for clearer mobile/tablet/desktop; minor hero spacing tweaks 2026-05-27 22:44:10 -07:00
Philip Peterson
2e5425606d Style tweaks 2026-05-27 22:28:12 -07:00
Philip Peterson
cd2d59f298 Tweak lifecycle to make more stateless, fix some styling 2026-05-27 21:58:23 -07:00
Philip Peterson
4232cded55 wip
All checks were successful
Build and push image / build (push) Successful in 20m26s
2026-05-25 00:32:23 -07:00