feat: polished appointment booking UI for LinkedIn CTA #6

Merged
forgejo_admin merged 2 commits from 5-feat-polished-appointment-booking-ui-for into main 2026-03-14 23:36:33 +00:00
Contributor

Summary

Replaces the bare placeholder static/index.html with a production-grade appointment booking page for Pal-E Agency's LinkedIn CTA. Professional consulting aesthetic with warm color palette, distinctive typography, mobile-first responsive design, and complete booking flow with error/success handling.

Changes

  • static/index.html -- Complete rewrite from 16-line placeholder to full booking UI:
    • Design: Warm cream/rust/charcoal palette, DM Serif Display headings + Inter body text (Google Fonts CDN), brand mark with "Pal-E Agency / DORA Elite AI Enterprise" tagline
    • Slot display: Fetches 7-day availability from GET /api/availability, splits large availability windows into 30-minute slots, groups by calendar day with "Today"/"Tomorrow" labels
    • Booking form: Name, email (validated), optional note with character limit. Selected slot shown in banner with "Change" option
    • Submission: Posts to POST /api/book, shows spinner during request, handles 409 conflicts and API errors gracefully
    • Success state: Confirmation with date/time details, Google Calendar link, "Book another" reset
    • Responsive: Mobile-first CSS, works at 375px/768px/1280px breakpoints
    • Accessibility: Skip link, ARIA labels/roles on slot grid and form, focus-visible outlines, prefers-reduced-motion support, semantic HTML
    • Zero dependencies: Vanilla HTML/CSS/JS, no frameworks, no build tools

Test Plan

  • Visit / and verify slots load for next 7 days
  • Select a slot, fill form, submit -- verify calendar event created
  • Test at 375px (mobile), 768px (tablet), 1280px (desktop) viewports
  • Test error: disconnect network, verify retry button works
  • Test conflict: book same slot twice, verify 409 error message
  • Test empty state: verify message when no slots available
  • Verify no console errors
  • Verify keyboard navigation (Tab through slots and form)

Review Checklist

  • No secrets committed
  • No unnecessary file changes (only static/index.html modified)
  • Commit messages are descriptive
  • No backend changes
  • No infrastructure changes
  • Closes #5
  • plan-pal-e-posts -- Phase 1 (gcal-scheduler Booking UI)
## Summary Replaces the bare placeholder `static/index.html` with a production-grade appointment booking page for Pal-E Agency's LinkedIn CTA. Professional consulting aesthetic with warm color palette, distinctive typography, mobile-first responsive design, and complete booking flow with error/success handling. ## Changes - `static/index.html` -- Complete rewrite from 16-line placeholder to full booking UI: - **Design**: Warm cream/rust/charcoal palette, DM Serif Display headings + Inter body text (Google Fonts CDN), brand mark with "Pal-E Agency / DORA Elite AI Enterprise" tagline - **Slot display**: Fetches 7-day availability from `GET /api/availability`, splits large availability windows into 30-minute slots, groups by calendar day with "Today"/"Tomorrow" labels - **Booking form**: Name, email (validated), optional note with character limit. Selected slot shown in banner with "Change" option - **Submission**: Posts to `POST /api/book`, shows spinner during request, handles 409 conflicts and API errors gracefully - **Success state**: Confirmation with date/time details, Google Calendar link, "Book another" reset - **Responsive**: Mobile-first CSS, works at 375px/768px/1280px breakpoints - **Accessibility**: Skip link, ARIA labels/roles on slot grid and form, focus-visible outlines, `prefers-reduced-motion` support, semantic HTML - **Zero dependencies**: Vanilla HTML/CSS/JS, no frameworks, no build tools ## Test Plan - [ ] Visit `/` and verify slots load for next 7 days - [ ] Select a slot, fill form, submit -- verify calendar event created - [ ] Test at 375px (mobile), 768px (tablet), 1280px (desktop) viewports - [ ] Test error: disconnect network, verify retry button works - [ ] Test conflict: book same slot twice, verify 409 error message - [ ] Test empty state: verify message when no slots available - [ ] Verify no console errors - [ ] Verify keyboard navigation (Tab through slots and form) ## Review Checklist - [x] No secrets committed - [x] No unnecessary file changes (only `static/index.html` modified) - [x] Commit messages are descriptive - [x] No backend changes - [x] No infrastructure changes ## Related - Closes #5 - `plan-pal-e-posts` -- Phase 1 (gcal-scheduler Booking UI)
feat: replace placeholder with polished appointment booking UI
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
561f2a7134
Professional consulting-aesthetic booking page for Pal-E Agency LinkedIn CTA.
Warm color palette (cream/rust/charcoal), DM Serif Display + Inter fonts,
mobile-first responsive design. Fetches 7-day availability from API, splits
windows into 30-min slots grouped by day, handles booking form with validation,
success confirmation with Google Calendar link, and graceful error states.

Closes #5

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: ARIA roles and resilient error handling from review
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
c2af53c145
- Replace role=listbox/option with role=group and aria-pressed on slot
  buttons (buttons inside listbox is semantically invalid)
- Add .catch() fallback before .json() on error responses so non-JSON
  errors (502 proxy, network timeouts) do not throw unhandled exceptions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Contributor

Self-Review Findings

Three issues identified and fixed in commit c2af53c:

1. ARIA semantic mismatch (accessibility)

Before: role="listbox" on slots grid with role="option" on <button> elements. Buttons inside a listbox is semantically invalid per WAI-ARIA spec -- listbox options must not be interactive elements.
Fix: Changed to role="group" on the grid and aria-pressed="true/false" on buttons (toggle button pattern).

2. Non-JSON error response crash (resilience)

Before: Error handling called res.json().then(...) directly. If the server returns a non-JSON error (e.g., 502 from a reverse proxy, or HTML error page), res.json() throws, and the user-facing error message is lost.
Fix: Added .catch(function() { return {}; }) before .then() so non-JSON responses gracefully fall through to the default error message. Applied to both /api/availability and /api/book fetch calls.

3. Submit button reset after success (cosmetic, not fixed)

The .finally() block resets the submit button text and disabled state even after a successful booking. This is harmless since the form is hidden by showSuccess(), so no user-visible impact. Left as-is to avoid adding state tracking complexity for zero UX benefit.

## Self-Review Findings Three issues identified and fixed in commit `c2af53c`: ### 1. ARIA semantic mismatch (accessibility) **Before:** `role="listbox"` on slots grid with `role="option"` on `<button>` elements. Buttons inside a listbox is semantically invalid per WAI-ARIA spec -- listbox options must not be interactive elements. **Fix:** Changed to `role="group"` on the grid and `aria-pressed="true/false"` on buttons (toggle button pattern). ### 2. Non-JSON error response crash (resilience) **Before:** Error handling called `res.json().then(...)` directly. If the server returns a non-JSON error (e.g., 502 from a reverse proxy, or HTML error page), `res.json()` throws, and the user-facing error message is lost. **Fix:** Added `.catch(function() { return {}; })` before `.then()` so non-JSON responses gracefully fall through to the default error message. Applied to both `/api/availability` and `/api/book` fetch calls. ### 3. Submit button reset after success (cosmetic, not fixed) The `.finally()` block resets the submit button text and disabled state even after a successful booking. This is harmless since the form is hidden by `showSuccess()`, so no user-visible impact. Left as-is to avoid adding state tracking complexity for zero UX benefit.
forgejo_admin deleted branch 5-feat-polished-appointment-booking-ui-for 2026-03-14 23:36:33 +00:00
Sign in to join this conversation.
No description provided.