Commit graph

52 commits

Author SHA1 Message Date
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
Philip Peterson
63ce2ba2ef wip 2026-05-24 19:23:05 -07:00
Mork Swork
cc2df201cd Mobile responsiveness
Some checks failed
Build and push image / build (push) Failing after 22s
2026-05-16 12:14:44 -07:00
Mork Swork
a1f1b5902e Tailwind 2026-05-16 11:45:33 -07:00
Mork Swork
ee265b679d Switch themes 2026-05-16 09:52:21 -07:00
Mork Swork
4649c56a58 Hamburger menu 2026-05-14 21:23:54 -07:00
Mork Swork
4ab06a69b5 Try to hide search 2026-05-14 20:52:42 -07:00
Mork Swork
f4d7c724cb Tweak top bar 2026-05-14 20:39:30 -07:00
Mork Swork
ed6ff4fbf6 Add front page, nav rebuild, and CI workflow
- Home controller with hero and services sections
- Nav rebuilt on install: Home, Services, About, FAQ, Contact (CTA), Book An Appointment (CTA)
- Entrypoint uses IS_SETUP check so failed installs retry on restart
- Gitea Actions workflow builds and pushes multi-arch image to forge.quinefoundation.com

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 20:05:46 -07:00
Mork Swork
7cc733a03e Style fixes 2026-05-13 21:14:57 -07:00
Mork Swork
9454dc03b4 wip flow 2026-05-13 15:26:33 -07:00
Mork Swork
0a2e80f7b0 wip booking flow 2026-05-13 14:55:52 -07:00
Mork Swork
269813c12d Use modal 2026-05-12 18:33:59 -07:00
Mork Swork
81c82c3da8 Structure 2026-05-12 17:28:47 -07:00