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)
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
# Task 12 — Wizard 3/4 pasos + Confirmation con reasons + anclar main ancho
|
||||
|
||||
## File changed
|
||||
- `src/pages/public/BookingPage.tsx` (only file touched)
|
||||
|
||||
## Steps applied (1–9)
|
||||
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.
|
||||
Reference in New Issue
Block a user