feat(03-06): wire EventDetailPopover Edit/Delete footer and implement DeleteConfirmationDialog

- EventDetailPopover: replace aria-hidden placeholder with Edit2/Trash2 footer buttons
  - Edit opens EventForm in edit mode and closes popover
  - Delete opens DeleteConfirmationDialog via setDeleteDialog (T-03-17 two-tap)
- DeleteConfirmationDialog: centered modal, max-width 320px, backdrop + focus trap
  - heading 'Delete event?', Fastmail body copy per UI-SPEC
  - Cancel/Escape close without deleting; Delete fires mutation
  - On success: setLastSyncedUid (feeds SyncStateToast), close dialog + popover
  - TanStack mutation; 48px Delete button (--color-destructive)
- CalendarShell: mount DeleteConfirmationDialog in both phone and tablet/desktop layouts
This commit is contained in:
Lucas Berger
2026-06-05 18:46:24 -04:00
parent 2fbeffee9a
commit 40322e11bf
3 changed files with 284 additions and 5 deletions
@@ -47,6 +47,7 @@ import { buildCalendarConfig, SX_FIRST_DAY_OF_WEEK } from '../lib/calendarConfig
import { useCalendarStore } from '../store/calendarStore.js'
import { EventDetailPopover } from './EventDetailPopover.js'
import { EventForm } from './EventForm.js'
import { DeleteConfirmationDialog } from './DeleteConfirmationDialog.js'
import { SyncStateToast } from './SyncStateToast.js'
import { AppNav } from './AppNav.js'
import { ColorLegend } from './ColorLegend.js'
@@ -355,6 +356,9 @@ export function CalendarShell() {
{/* EventForm modal — conditionally rendered while eventFormOpen */}
{eventFormOpen && <EventForm />}
{/* DeleteConfirmationDialog — always mounted; renders nothing when deleteDialogOpen is false */}
<DeleteConfirmationDialog />
{/* SyncStateToast — always mounted; renders nothing when lastSyncedUid is null */}
<SyncStateToast />
</div>
@@ -429,6 +433,9 @@ export function CalendarShell() {
{/* EventForm modal — conditionally rendered while eventFormOpen */}
{eventFormOpen && <EventForm />}
{/* DeleteConfirmationDialog — always mounted; renders nothing when deleteDialogOpen is false */}
<DeleteConfirmationDialog />
{/* SyncStateToast — always mounted; renders nothing when lastSyncedUid is null */}
<SyncStateToast />
</div>