From 69eac90bab169029901df25a71a5c9b57a4f6151 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Fri, 5 Jun 2026 18:30:25 -0400 Subject: [PATCH] feat(03-05): mount EventForm + add New Event FAB/toolbar trigger in CalendarShell - Import EventForm and Plus icon from lucide-react - Phone: fixed FAB bottom-right (56px, dark neutral fill per UI-SPEC) - Tablet/desktop: toolbar button above calendar content area - Both trigger setEventForm(true, 'create') via Zustand - EventForm conditionally rendered while eventFormOpen - Selectors pattern preserved to avoid unnecessary re-renders (Bug B guard) --- apps/pwa/src/components/CalendarShell.tsx | 76 ++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/apps/pwa/src/components/CalendarShell.tsx b/apps/pwa/src/components/CalendarShell.tsx index e05c6a3..7e4c1ad 100644 --- a/apps/pwa/src/components/CalendarShell.tsx +++ b/apps/pwa/src/components/CalendarShell.tsx @@ -39,12 +39,14 @@ import { type CalendarType, } from '@schedule-x/calendar' import { createEventsServicePlugin } from '@schedule-x/events-service' +import { Plus } from 'lucide-react' import { fetchMe, fetchEvents } from '../api/client.js' import { hydrateEvents } from '../lib/hydrateEvents.js' import { buildCalendarConfig, SX_FIRST_DAY_OF_WEEK } from '../lib/calendarConfig.js' import { useCalendarStore } from '../store/calendarStore.js' import { EventDetailPopover } from './EventDetailPopover.js' +import { EventForm } from './EventForm.js' import { AppNav } from './AppNav.js' import { ColorLegend } from './ColorLegend.js' import { SkeletonCalendar } from './SkeletonCalendar.js' @@ -75,6 +77,8 @@ export function CalendarShell() { const setCalendarRange = useCalendarStore((s) => s.setCalendarRange) const setOpenEventId = useCalendarStore((s) => s.setOpenEventId) const selectedView = useCalendarStore((s) => s.selectedView) + const setEventForm = useCalendarStore((s) => s.setEventForm) + const eventFormOpen = useCalendarStore((s) => s.eventFormOpen) const { start, end } = calendarRange const queryClient = useQueryClient() @@ -297,7 +301,7 @@ export function CalendarShell() { // ── Full layout ──────────────────────────────────────────────────────────── if (phone) { - // Phone: stacked layout — AppNav top bar + content below + // Phone: stacked layout — AppNav top bar + content below + FAB return (
+ + {/* New Event FAB — phone: bottom-right floating action button (UI-SPEC §Interaction Contract) */} + + + {/* EventForm modal — conditionally rendered while eventFormOpen */} + {eventFormOpen && }
) } @@ -345,11 +380,50 @@ export function CalendarShell() { {/* Main content area */}
+ + {/* New Event toolbar button — tablet/desktop (UI-SPEC §Interaction Contract) */} +
+ +
+
{/* EventDetailPopover — standalone mode driven by Zustand openEventId */} + + {/* EventForm modal — conditionally rendered while eventFormOpen */} + {eventFormOpen && } ) }