Files
fete/specs/009-list-events/data-model.md
nitrix e56998b17c
All checks were successful
CI / backend-test (push) Successful in 57s
CI / frontend-test (push) Successful in 22s
CI / frontend-e2e (push) Successful in 1m4s
CI / build-and-publish (push) Has been skipped
Add event list feature (009-list-events)
Enable users to see all their saved events on the home screen, sorted
by date with upcoming events first. Key capabilities:

- EventCard with title, relative time display, and organizer/attendee
  role badge
- Sortable EventList with past-event visual distinction (faded style)
- Empty state when no events are stored
- Swipe-to-delete gesture with confirmation dialog
- Floating action button for quick event creation
- Rename router param :token → :eventToken across all views
- useRelativeTime composable (Intl.RelativeTimeFormat)
- useEventStorage: add validation, removeEvent(), reactive versioning
- Full E2E and unit test coverage for all new components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:53:55 +01:00

2.8 KiB

Data Model: Event List on Home Page

Feature: 009-list-events | Date: 2026-03-08

Entities

StoredEvent (existing — no changes)

The StoredEvent interface in frontend/src/composables/useEventStorage.ts already contains all fields needed for the event list feature.

interface StoredEvent {
  eventToken: string        // Required — UUID, used for navigation
  organizerToken?: string   // Present if user created this event
  title: string             // Required — displayed on card
  dateTime: string          // Required — ISO 8601, used for sorting + relative time
  expiryDate: string        // Stored but not displayed in list view
  rsvpToken?: string        // Present if user RSVP'd to this event
  rsvpName?: string         // User's name at RSVP time
}

Validation Rules

An event entry is considered valid for display if all of:

  • eventToken is a non-empty string
  • title is a non-empty string
  • dateTime is a non-empty string that parses to a valid Date

Invalid entries are silently excluded from the list (FR-010).

Derived Properties (computed at render time)

Property Derivation
isPast new Date(dateTime) < new Date()
isOrganizer organizerToken !== undefined
isAttendee rsvpToken !== undefined && organizerToken === undefined
relativeTime Intl.RelativeTimeFormat applied to dateTime vs now
detailRoute /events/${eventToken}

Sorting Order

  1. Upcoming events (dateTime >= now): ascending by dateTime (soonest first)
  2. Past events (dateTime < now): descending by dateTime (most recently passed first)

Composable Extension

The useEventStorage composable needs one new function:

function removeEvent(eventToken: string): void {
  const events = readEvents().filter((e) => e.eventToken !== eventToken)
  writeEvents(events)
}

Returned alongside existing functions from useEventStorage().

State Transitions

localStorage read
       │
       ▼
  Parse JSON ──(error)──► empty array
       │
       ▼
  Validate entries ──(invalid)──► silently excluded
       │
       ▼
  Split: upcoming / past
       │
       ▼
  Sort each group
       │
       ▼
  Concatenate ──► rendered list

Remove Event Flow

User taps delete icon / swipes left
       │
       ▼
  ConfirmDialog opens
       │
  ┌────┴────┐
  │ Cancel  │  Confirm
  │         │     │
  │         ▼     ▼
  │    removeEvent(token)
  │         │
  │         ▼
  │    Event removed from localStorage
  │    List re-renders (event disappears)
  └────────────────────────────────┘