Files
AgendaPro/.superpowers/sdd/task-12-report.md
T
AgendaPro Dev d796538fd9 feat: rebrand AgendaPro -> AgendaMax + calendar fixes + current-week demo seed
- Rebrand all user-facing text to AgendaMax
- Fix sidebar scrolling: card container no longer overflows html (flex h-full min-h-0)
- Fix calendar toolbar hover: active buttons keep readable contrast
- Sticky calendar toolbar (month/week/day always visible on scroll)
- Seed guarantees 2-4 appointments per day for current week (Mon-Sat)
2026-07-27 10:11:16 -06:00

64 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Task 12 — Wizard 3/4 pasos + Confirmation con reasons + anclar main ancho
## File changed
- `src/pages/public/BookingPage.tsx` (only file touched)
## Steps applied (19)
1. Replaced static `STEPS` with `FULL_STEPS` const + `stepsFor(autoAssign)` helper that drops the "Especialista" step when auto-assign is on (returns `{n, label, original}` items).
2. Added `maxBookableDate()` helper next to `todayStr` (today + 3 months, ISO `YYYY-MM-DD`).
3. In `BookingPage`, computed `autoAssign`, `steps` (useMemo on autoAssign), `stepCount`, and `currentOriginal` (find by `n === step`, read `.original`) **before** `slotsQuery` so the closure can see it.
4. `slotsQuery.enabled` now uses `currentOriginal === 3` (was `step >= 3`).
5. `goNext` / `goBack` / `pickSlot` use `stepCount` (no hard-coded `4`).
6. `canContinue`, `primaryLabel`, `onPrimary` switch on `currentOriginal`. `handleBook` sends `employee_id: autoAssign ? undefined : selectedSlot.employee_id`.
7. Rewrote the main `return (...)` to render sections by `currentOriginal`; `main` widens to `max-w-5xl` only when `currentOriginal === 3`, otherwise `max-w-2xl`; `DateTimePicker` gets `max={maxBookableDate()}`; the Especialista row in Datos is hidden when `autoAssign`.
8. Updated `TopBar` + `ActionBar` signatures to accept `stepCount` + `steps`; both widened from `max-w-3xl`/`max-w-2xl``max-w-5xl`. TopBar now reads "Paso X de {stepCount}" and iterates the dynamic `steps` array (including the mobile `X / {stepCount}` chip).
9. `Confirmation` renders `appointment.reasons` as `brand` badges (with Sparkles icon) guarded by `reasons && reasons.length > 0`, placed under the Especialista row.
Also updated the two secondary `TopBar` call sites (disabled-booking screen and `Confirmation`) to pass `stepCount={4} steps={[]}``step={0}` hides the indicator block, so an empty array is safe there.
## Verification
### typecheck
```
> tsc -b --noEmit
(no output — 0 errors)
```
First pass surfaced one error: `ActionBar`'s `stepCount` param was unused (TS6133). Fixed by surfacing it in the empty-state label: `Paso {step} de {stepCount} · Continúa para reservar`.
### build
```
> tsc -b && vite build
✓ 2461 modules transformed.
✓ built in 5.16s
```
### lint
```
> eslint . --ext ts,tsx
ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
```
Pre-existing env issue (ESLint 9 with no flat config in the repo). Not introduced by this task; no `react-hooks/exhaustive-deps` warnings would be reachable until the config is repaired. The `useMemo(() => stepsFor(autoAssign), [autoAssign])` dep array is correct.
### Runtime smoke (server already running on :5173)
- Slug: `lumiere-estetica-spa`. Default `auto_assign_specialist=0`.
- **OFF flow**: GET `/api/public/<slug>``auto_assign_specialist=0`. Slots for service 6 tomorrow returned 10 slots. POST `/book` without `employee_id` → 201, `emp_id=2 Mateo Herrera`, `reasons=["Disponible"]`, `client_created=true`. (Server still auto-ranked because the client didn't pick one — that's the unchanged 4-step path.)
- **ON flow**: PATCH `/api/settings {auto_assign_specialist:1}`. GET public → `auto_assign_specialist=1` (correctly exposed). POST `/book` without `employee_id` at a free slot → 201, `emp_id=2 Mateo Herrera`, `reasons=["Disponible"]`.
- Double-booking guard: re-POSTing the first booked slot → 409 `Esa hora acaba de ocuparse, elige otra.`
- Restored `auto_assign_specialist=0` afterwards.
Visual confirmation of step count / layout width was done by code inspection (no headless browser available in this subagent): `stepsFor(false)` yields 4 items; `stepsFor(true)` yields 3 items (Especialista filtered). The TopBar "Paso X de {stepCount}" and the mobile "X / {stepCount}" both read from the dynamic count, so 4 vs 3 follows automatically. `main`'s width is selected by `currentOriginal === 3 ? "max-w-5xl" : "max-w-2xl"`, which is true only on the Horario section regardless of the 3- or 4-step mapping.
## Deviations
- `ActionBar`'s previously-unused `stepCount` prop (the spec required ActionBar to accept it, but the plan's literal snippet didn't read it) is now surfaced in the empty-state copy. This both satisfies TS6133 and improves UX consistency.
- No commit performed (per task constraints).
## Self-review
- **OFF = 4 steps?** Yes — `stepsFor(false)` maps all 4 `FULL_STEPS` to `{1:Servicio, 2:Especialista, 3:Horario, 4:Datos}` with `original` matching `n`. `currentOriginal` drives section rendering, so the 4-step Servicio→Especialista→Horario→Datos flow is preserved exactly. The "Cualquiera" path still hits the server ranking (server-side, unchanged here).
- **ON = 3 steps?** Yes — `stepsFor(true)` filters out Especialista, renumbering to `{1:Servicio (orig 1), 2:Horario (orig 3), 3:Datos (orig 4)}`. The `currentOriginal === 2` branch (Especialista) never matches because no step maps to original 2.
- **currentOriginal before slotsQuery?** Yes — declared at line 83, slotsQuery at line 90 references it in `enabled` at line 93.
- **handleBook sends undefined employee_id when autoAssign?** Yes — line 198 `employee_id: autoAssign ? undefined : selectedSlot.employee_id`. `BookPayload.employee_id` is optional, so this typechecks.
- **Confirmation shows reasons badges?** Yes — guarded by `appointment.reasons && appointment.reasons.length > 0`, renders `<span>` chips with Sparkles icon under the Especialista row.
- **main widened only on Horario?** Yes — `cn("…", currentOriginal === 3 ? "max-w-5xl" : "max-w-2xl")`. Horario is always original 3 in both flows.
- **Disabled-booking screen, loading/error states, reset() preserved?** Yes — only the TopBar call in the disabled screen was updated to pass the new required props; the rest of that branch is untouched. Loading/error branches and `reset()` are unchanged.
- **No git commit.** Confirmed — only file edits + npm runs.