- 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)
3.2 KiB
3.2 KiB
Task 11 — DateTimePicker 2-col + month calendar + Mañana/Tarde grouping
File changed
src/pages/public/BookingPage.tsx- Added
import { MonthCalendar } from "../../components/MonthCalendar";(line 28). - Rewrote
DateTimePicker(now lines 556–639): 2-column grid onmd+, vertical stack belowmd, new optionalmax?: stringprop, slots grouped via newSlotGroupsubcomponent. - Added new
SlotGrouphelper (lines 641–681).
- Added
Verification results
npm run typecheck
> tsc -b --noEmit
0 errors. The existing caller of DateTimePicker (in BookingPage) does not pass max — confirms max is optional and not breaking the caller.
npm run build
✓ 2461 modules transformed.
✓ built in 4.98s
Succeeds. Production bundle emitted.
Visual smoke
Not executed interactively (subagent has no browser). Validated indirectly via successful vite build (2461 modules transformed, including the rewritten BookingPage and the imported MonthCalendar). Task 12 is responsible for wiring max/employeeId end-to-end and for any final interactive smoke; the unit of work in this task compiles and type-checks cleanly against the rest of the project.
Self-review
| Check | Result |
|---|---|
2-col layout only on md+ |
✅ Outer wrapper uses md:grid md:grid-cols-[minmax(0,1fr)_minmax(0,1.1fr)] md:items-start md:gap-8. Below md no grid is applied. |
| Mobile stacked vertically | ✅ Right column wrapper has mt-4 md:mt-0 so on mobile the calendar card is followed by the slots card with vertical spacing; the outer div is a plain block (no flex/grid) below md. |
| Slot button markup unchanged | ✅ Identical classes (grid grid-cols-3 gap-2 sm:grid-cols-4; button rounded-xl border px-2 py-2.5 text-sm font-bold transition-all; active border-brand-500 bg-brand-500 text-white shadow-soft; inactive border-slate-200 bg-white text-slate-700 hover:border-brand-400 hover:bg-brand-50), same key={${slot.iso}-${slot.employee_id}}, same onClick={() => onPick(slot)}. Only the grouping wrapper (SlotGroup) is new. |
| Morning/afternoon split correct, incl. 12 PM boundary | ✅ Algorithm: parse (\d{1,2}):(\d{2}) → h; pm = /PM/i; hour24 = pm && h!==12 ? h+12 : !pm && h===12 ? 0 : h; bucket by hour24 < 12. Verified cases: 12:00 AM → h=12, !pm, h===12 → 0 → Mañana. 11:30 AM → 11 → Mañana. 12:00 PM → h=12, pm, h===12 (no +12) → 12 → Tarde. 12:30 PM → 12 → Tarde. 1:00 PM → 13 → Tarde. 11:59 PM → 23 → Tarde. Boundary at noon is correct (12:00 PM is the first Tarde slot). |
max is optional |
✅ Declared max?: string. Typecheck with caller that omits max passes. |
| No commit performed | ✅ No git commit run. |
Scope respected (only BookingPage.tsx, only DateTimePicker + import + SlotGroup) |
✅ No other functions touched (TopBar, ActionBar, Confirmation, EmployeeList, ServiceGrid, DetailsForm unchanged; Task 8's pl-10 untouched). |
Concerns
- None. Implementation matches the plan verbatim. Interactive browser smoke deferred to the orchestrator / Task 12 (which will also pass
maxandemployeeIdto the picker and exercise the full wizard).