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>
This commit is contained in:
145
specs/009-list-events/spec.md
Normal file
145
specs/009-list-events/spec.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Feature Specification: Event List on Home Page
|
||||
|
||||
**Feature Branch**: `009-list-events`
|
||||
**Created**: 2026-03-08
|
||||
**Status**: Draft
|
||||
**Input**: User description: "man kann auf der hauptseite eine liste an events sehen, sofern sie im localstorage gespeichert sind"
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - View My Events (Priority: P1)
|
||||
|
||||
As a returning user, I want to see a list of events I have previously created or interacted with (RSVP'd to) on the home page, so I can quickly navigate back to them without needing to remember or bookmark individual event links.
|
||||
|
||||
The home page displays all events stored in the browser's local storage. Each event entry shows the event title and date/time. Tapping an event navigates to its detail page.
|
||||
|
||||
**Why this priority**: This is the core value of the feature — without the list, the home page remains a dead end for returning users.
|
||||
|
||||
**Independent Test**: Can be fully tested by creating an event (or simulating localStorage entries), returning to the home page, and verifying all stored events appear in a list with correct titles and dates.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the user has 3 events stored in localStorage, **When** they visit the home page, **Then** all 3 events are displayed in a list showing title and date/time for each.
|
||||
2. **Given** the user has events stored in localStorage, **When** they tap on an event in the list, **Then** they are navigated to the event detail page (`/events/:eventToken`).
|
||||
3. **Given** the user has events stored in localStorage, **When** they visit the home page, **Then** events are sorted by date/time (nearest upcoming event first, past events last).
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Empty State (Priority: P2)
|
||||
|
||||
As a new user with no stored events, I see an inviting empty state on the home page that encourages me to create my first event or explains how to get started.
|
||||
|
||||
**Why this priority**: First-time users need clear guidance. The empty state is the first impression for new users.
|
||||
|
||||
**Independent Test**: Can be tested by clearing localStorage and visiting the home page — the empty state message and "Create Event" call-to-action should be visible.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** no events are stored in localStorage, **When** the user visits the home page, **Then** an empty state message is displayed (e.g., "No events yet") with a prominent "Create Event" button.
|
||||
2. **Given** the user has at least one event stored, **When** they visit the home page, **Then** the empty state message is not shown — the event list is displayed instead.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Remove Event from List (Priority: P3)
|
||||
|
||||
As a user, I want to remove an event from my personal list so I can keep my home page tidy and only show events I still care about.
|
||||
|
||||
**Why this priority**: Housekeeping capability. Without removal, the list grows indefinitely and becomes cluttered over time.
|
||||
|
||||
**Independent Test**: Can be tested by having multiple events in localStorage, removing one from the list, and verifying it disappears from the home page while the others remain.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the user has events in their list, **When** they tap the delete icon on an event card, **Then** a confirmation prompt appears asking if they are sure.
|
||||
1b. **Given** the user has events in their list, **When** they swipe an event card to the left, **Then** a confirmation prompt appears asking if they are sure.
|
||||
2. **Given** the confirmation prompt is shown, **When** the user confirms removal, **Then** the event is removed from localStorage and disappears from the list immediately.
|
||||
3. **Given** the confirmation prompt is shown, **When** the user cancels, **Then** the event remains in the list unchanged.
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - Past Events Appear Faded (Priority: P2)
|
||||
|
||||
As a user, I want events whose date/time has passed to appear visually faded or muted in the list, so I can immediately focus on upcoming events without past events cluttering my attention.
|
||||
|
||||
The fading should feel modern and polished — not a blunt grey-out, but a subtle reduction in contrast and saturation that makes past events recede visually while remaining readable and tappable.
|
||||
|
||||
**Why this priority**: Without this, past and upcoming events look identical, making the list harder to scan. This is essential for usability once a user has accumulated several events.
|
||||
|
||||
**Independent Test**: Can be tested by having both future and past events in localStorage and verifying that past events display with reduced visual prominence while remaining interactive.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the user has a past event (dateTime before now) in localStorage, **When** they view the home page, **Then** the event appears with reduced visual prominence (muted colors, lower contrast) compared to upcoming events.
|
||||
2. **Given** the user has a past event in the list, **When** they tap on it, **Then** it still navigates to the event detail page — it remains fully interactive.
|
||||
3. **Given** the user has both past and upcoming events, **When** they view the home page, **Then** upcoming events appear first (full visual prominence), followed by past events (faded), creating a clear visual hierarchy.
|
||||
|
||||
---
|
||||
|
||||
### User Story 5 - Visual Distinction for Event Roles (Priority: P3)
|
||||
|
||||
As a user, I want to see at a glance whether I am the organizer of an event or just an attendee, so I can quickly identify my responsibilities.
|
||||
|
||||
**Why this priority**: Nice-to-have clarity. The data is already available in localStorage (presence of `organizerToken`), so surfacing it improves usability at low effort.
|
||||
|
||||
**Independent Test**: Can be tested by having both created events (with organizerToken) and RSVP'd events (with rsvpToken) in localStorage, and verifying they display different visual indicators.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the user has a created event (organizerToken present) in localStorage, **When** they view the home page, **Then** the event shows a visual indicator marking them as the organizer (e.g., a badge or label).
|
||||
2. **Given** the user has an event with an RSVP (rsvpToken present, no organizerToken) in localStorage, **When** they view the home page, **Then** the event shows a visual indicator marking them as an attendee.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- What happens when localStorage data is corrupted or contains invalid entries? Events with missing required fields (eventToken, title, dateTime) are silently excluded from the list.
|
||||
- What happens when localStorage is unavailable (e.g., private browsing with storage disabled)? The empty state is shown with the "Create Event" button — the app remains functional.
|
||||
- What happens when an event's date/time has passed? The event remains in the list but appears visually faded.
|
||||
- What happens when the user has a very large number of stored events (e.g., 50+)? The list scrolls naturally. No pagination is needed at this scale since localStorage entries are lightweight.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: System MUST display a list of all events stored in the browser's local storage on the home page.
|
||||
- **FR-002**: Each event entry MUST show the event title and the event date/time displayed as a relative time label (e.g., "in 3 days", "yesterday") using `Intl.RelativeTimeFormat`.
|
||||
- **FR-003**: Each event entry MUST be tappable/clickable and navigate to the event detail page (`/events/:eventToken`).
|
||||
- **FR-004**: Events MUST be sorted by date/time with nearest upcoming events first and past events last.
|
||||
- **FR-005**: System MUST display an empty state with a "Create Event" call-to-action when no events are stored.
|
||||
- **FR-006a**: Users MUST be able to remove individual events from their local list via a visible delete icon on each event card (primary mechanism, implemented first).
|
||||
- **FR-006b**: Users MUST be able to remove individual events via swipe-to-delete gesture (secondary mechanism, implemented separately after FR-006a).
|
||||
- **FR-007**: System MUST show a confirmation prompt before removing an event from the list.
|
||||
- **FR-008**: System MUST visually distinguish events where the user is the organizer from events where the user is an attendee.
|
||||
- **FR-009**: System MUST display past events (dateTime before current time) with reduced visual prominence — muted colors and lower contrast — while keeping them readable and interactive.
|
||||
- **FR-010**: System MUST gracefully handle corrupted or incomplete localStorage entries by excluding invalid events from the list.
|
||||
- **FR-011**: The "Create Event" button MUST remain accessible on the home page even when events are listed, implemented as a Floating Action Button (FAB) fixed at the bottom-right corner.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **Stored Event**: A locally persisted reference to an event the user has interacted with. Contains: event token (unique identifier for navigation), title, date/time, expiry date, and optionally an organizer token (if created by this user) or RSVP token and name (if the user RSVP'd).
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: Users can see all their stored events on the home page within 1 second of page load.
|
||||
- **SC-002**: Users can navigate from the home page to any event detail page in a single tap/click.
|
||||
- **SC-003**: Users can remove an unwanted event from their list in under 3 seconds (including confirmation).
|
||||
- **SC-004**: New users (no stored events) see a clear call-to-action to create their first event.
|
||||
- **SC-005**: Users can distinguish their role (organizer vs. attendee) for each event at a glance without opening the event.
|
||||
|
||||
## Clarifications
|
||||
|
||||
### Session 2026-03-08
|
||||
|
||||
- Q: How does the user trigger event removal? → A: Two mechanisms — visible delete icon on each event card (primary, implemented first) and swipe-to-delete gesture (secondary, implemented separately after).
|
||||
- Q: Placement of "Create Event" button when events exist? → A: Floating Action Button (FAB) fixed at bottom-right corner.
|
||||
- Q: Date/time display format in event list? → A: Relative time labels ("in 3 days", "yesterday") via Intl.RelativeTimeFormat.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- The existing `useEventStorage` composable and `StoredEvent` interface provide all necessary data for the event list (no backend API calls needed for listing).
|
||||
- The event list is purely client-side — there is no server-side "my events" endpoint. Privacy is preserved because events are only known to the user's browser.
|
||||
- The event list uses `Intl.RelativeTimeFormat` for relative time labels (FR-002), while the event detail view uses `Intl.DateTimeFormat` for absolute date/time display. Both use the browser's locale (`navigator.language`).
|
||||
- The "Create Event" flow (spec 006) already saves events to localStorage, so no changes to event creation are needed.
|
||||
- The RSVP flow (spec 008) already saves RSVP data to localStorage, so no changes to RSVP are needed.
|
||||
Reference in New Issue
Block a user