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>
216 lines
11 KiB
Markdown
216 lines
11 KiB
Markdown
# Tasks: Event List on Home Page
|
||
|
||
**Input**: Design documents from `/specs/009-list-events/`
|
||
**Prerequisites**: plan.md, spec.md, research.md, data-model.md
|
||
|
||
**Tests**: Unit tests (Vitest) and E2E tests (Playwright) are included per constitution (Principle II: Test-Driven Methodology).
|
||
|
||
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
|
||
|
||
## Format: `[ID] [P?] [Story] Description`
|
||
|
||
- **[P]**: Can run in parallel (different files, no dependencies)
|
||
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
|
||
- Include exact file paths in descriptions
|
||
|
||
---
|
||
|
||
## Phase 1: Setup (Shared Infrastructure)
|
||
|
||
**Purpose**: Composable extensions and utility functions shared across all user stories
|
||
|
||
- [x] T000 Rename router param `:token` to `:eventToken` in `frontend/src/router/index.ts` and update all references in `EventDetailView.vue`, `EventStubView.vue`, and their test files (consistency with `StoredEvent.eventToken` field name)
|
||
- [x] T001 Add `isValidStoredEvent` type guard and validation filter to `frontend/src/composables/useEventStorage.ts` (FR-010)
|
||
- [x] T002 Add `removeEvent(eventToken: string)` function to `frontend/src/composables/useEventStorage.ts` (needed by US3)
|
||
- [x] T003 [P] Create `useRelativeTime` composable in `frontend/src/composables/useRelativeTime.ts` (Intl.RelativeTimeFormat wrapper, FR-002)
|
||
- [x] T004 [P] Add unit tests for `isValidStoredEvent` and `removeEvent` in `frontend/src/composables/__tests__/useEventStorage.spec.ts`
|
||
- [x] T005 [P] Create unit tests for `useRelativeTime` in `frontend/src/composables/__tests__/useRelativeTime.spec.ts`
|
||
|
||
**Checkpoint**: Composable layer complete — all shared logic tested and available for components.
|
||
|
||
---
|
||
|
||
## Phase 2: User Story 1 — View My Events (Priority: P1) 🎯 MVP
|
||
|
||
**Goal**: Home page shows all stored events in a sorted list with title and relative time. Tapping navigates to event detail.
|
||
|
||
**Independent Test**: Simulate localStorage entries, visit home page, verify all events appear sorted with correct titles and relative times. Tap an event and verify navigation to `/events/:eventToken`.
|
||
|
||
### Unit Tests for User Story 1
|
||
|
||
- [x] T006 [P] [US1] Create unit tests for EventCard component in `frontend/src/components/__tests__/EventCard.spec.ts` — include test cases for `isPast` prop (faded styling) and role badge rendering (organizer vs. attendee)
|
||
- [x] T007 [P] [US1] Create unit tests for EventList component in `frontend/src/components/__tests__/EventList.spec.ts`
|
||
|
||
### Implementation for User Story 1
|
||
|
||
- [x] T008 [P] [US1] Create `EventCard.vue` component in `frontend/src/components/EventCard.vue` — displays title, relative time, role badge; emits click for navigation
|
||
- [x] T009 [US1] Create `EventList.vue` component in `frontend/src/components/EventList.vue` — reads events from composable, validates, sorts (upcoming asc, past desc), renders EventCard list
|
||
- [x] T010 [US1] Refactor `HomeView.vue` in `frontend/src/views/HomeView.vue` — integrate EventList, conditionally show list when events exist
|
||
- [x] T011 [US1] Add event card and list styles to `frontend/src/assets/main.css`
|
||
|
||
### E2E Tests for User Story 1
|
||
|
||
- [x] T012 [US1] Create E2E test file `frontend/e2e/home-events.spec.ts` — tests: events displayed with title and relative time, sorted correctly, click navigates to detail page
|
||
|
||
**Checkpoint**: MVP complete — returning users see their events and can navigate to details.
|
||
|
||
---
|
||
|
||
## Phase 3: User Story 2 — Empty State (Priority: P2)
|
||
|
||
**Goal**: New users with no stored events see an inviting empty state with a "Create Event" call-to-action.
|
||
|
||
**Independent Test**: Clear localStorage, visit home page, verify empty state message and "Create Event" button are visible.
|
||
|
||
### Unit Tests for User Story 2
|
||
|
||
- [x] T013 [P] [US2] Create unit tests for EmptyState component in `frontend/src/components/__tests__/EmptyState.spec.ts`
|
||
|
||
### Implementation for User Story 2
|
||
|
||
- [x] T014 [US2] Create `EmptyState.vue` component in `frontend/src/components/EmptyState.vue` — shows message and "Create Event" RouterLink
|
||
- [x] T015 [US2] Update `HomeView.vue` in `frontend/src/views/HomeView.vue` — show EmptyState when no valid events, show EventList otherwise
|
||
- [x] T016 [US2] Add empty state styles to `frontend/src/assets/main.css`
|
||
|
||
### E2E Tests for User Story 2
|
||
|
||
- [x] T017 [US2] Add E2E tests to `frontend/e2e/home-events.spec.ts` — tests: empty state shown when no events, hidden when events exist
|
||
|
||
**Checkpoint**: Home page handles both new and returning users.
|
||
|
||
---
|
||
|
||
## Phase 4: User Story 4 — Past Events Appear Faded (Priority: P2)
|
||
|
||
**Goal**: Events whose date/time has passed appear with reduced visual prominence (muted colors, lower contrast) while remaining interactive.
|
||
|
||
**Independent Test**: Have both future and past events in localStorage, verify past events display faded while remaining clickable.
|
||
|
||
### Implementation for User Story 4
|
||
|
||
- [x] T018 [US4] Add `.event-card--past` modifier class with `opacity: 0.6; filter: saturate(0.5)` to `frontend/src/components/EventCard.vue` or `frontend/src/assets/main.css`
|
||
- [x] T019 [US4] Pass `isPast` computed property to EventCard in `EventList.vue` and apply modifier class in `frontend/src/components/EventCard.vue`
|
||
|
||
### E2E Tests for User Story 4
|
||
|
||
- [x] T020 [US4] Add E2E tests to `frontend/e2e/home-events.spec.ts` — tests: past events have faded class, upcoming events do not, past events remain clickable
|
||
|
||
**Checkpoint**: Visual hierarchy distinguishes upcoming from past events.
|
||
|
||
---
|
||
|
||
## Phase 5: User Story 3 — Remove Event from List (Priority: P3)
|
||
|
||
**Goal**: Users can remove events from their local list via delete icon (and later swipe) with confirmation.
|
||
|
||
**Independent Test**: Have multiple events, remove one via delete icon, verify it disappears while others remain.
|
||
|
||
### Unit Tests for User Story 3
|
||
|
||
- [x] T021 [P] [US3] Create unit tests for ConfirmDialog component in `frontend/src/components/__tests__/ConfirmDialog.spec.ts`
|
||
|
||
### Implementation for User Story 3
|
||
|
||
- [x] T022 [US3] Create `ConfirmDialog.vue` component in `frontend/src/components/ConfirmDialog.vue` — teleport-to-body modal with confirm/cancel, focus trapping, Escape key
|
||
- [x] T023 [US3] Add delete icon button to `EventCard.vue` in `frontend/src/components/EventCard.vue` — emits `delete` event with eventToken (FR-006a)
|
||
- [x] T024 [US3] Wire delete flow in `EventList.vue` in `frontend/src/components/EventList.vue` — listen for delete event, show ConfirmDialog, call `removeEvent()` on confirm
|
||
- [x] T025 [US3] Add delete icon and confirm dialog styles to `frontend/src/assets/main.css`
|
||
|
||
### E2E Tests for User Story 3
|
||
|
||
- [x] T026 [US3] Add E2E tests to `frontend/e2e/home-events.spec.ts` — tests: delete icon visible, confirmation dialog appears, confirm removes event, cancel keeps event
|
||
|
||
**Checkpoint**: Users can manage their event list.
|
||
|
||
---
|
||
|
||
## Phase 6: User Story 5 — Visual Distinction for Event Roles (Priority: P3)
|
||
|
||
**Goal**: Events show a badge indicating whether the user is the organizer or an attendee.
|
||
|
||
**Independent Test**: Have events with organizerToken and rsvpToken in localStorage, verify different badges displayed.
|
||
|
||
### Implementation for User Story 5
|
||
|
||
- [x] T027 [US5] Add role badge (Organizer/Attendee) to `EventCard.vue` in `frontend/src/components/EventCard.vue` — derive from organizerToken/rsvpToken presence
|
||
- [x] T028 [US5] Add role badge styles to `frontend/src/assets/main.css`
|
||
|
||
### E2E Tests for User Story 5
|
||
|
||
- [x] T029 [US5] Add E2E tests to `frontend/e2e/home-events.spec.ts` — tests: organizer badge shown for events with organizerToken, attendee badge for events with rsvpToken only
|
||
|
||
**Checkpoint**: Role distinction visible at a glance.
|
||
|
||
---
|
||
|
||
## Phase 7: Polish & Cross-Cutting Concerns
|
||
|
||
**Purpose**: FAB, swipe gesture, accessibility, and final polish
|
||
|
||
- [x] T030 Create `CreateEventFab.vue` in `frontend/src/components/CreateEventFab.vue` — fixed FAB at bottom-right, navigates to `/create` (FR-011)
|
||
- [x] T031 Add FAB to `HomeView.vue` in `frontend/src/views/HomeView.vue` — visible when events exist (empty state has its own CTA)
|
||
- [x] T032 Add FAB styles to `frontend/src/assets/main.css`
|
||
- [x] T033 Implement swipe-to-delete gesture on EventCard in `frontend/src/components/EventCard.vue` — native Touch API (FR-006b)
|
||
- [x] T034 Accessibility review: verify ARIA labels, keyboard navigation (Tab/Enter/Escape), focus trapping in ConfirmDialog, WCAG AA contrast on faded cards
|
||
- [x] T035 Add E2E tests for FAB to `frontend/e2e/home-events.spec.ts` — tests: FAB visible when events exist, navigates to create page
|
||
|
||
---
|
||
|
||
## Dependencies & Execution Order
|
||
|
||
### Phase Dependencies
|
||
|
||
- **Phase 1 (Setup)**: No dependencies — start immediately
|
||
- **Phase 2 (US1)**: Depends on T001, T003 (validation + relative time composable)
|
||
- **Phase 3 (US2)**: Depends on T001 (validation); can run in parallel with US1
|
||
- **Phase 4 (US4)**: Depends on Phase 2 completion (EventCard must exist)
|
||
- **Phase 5 (US3)**: Depends on Phase 2 completion (EventList must exist) + T002 (removeEvent)
|
||
- **Phase 6 (US5)**: Depends on Phase 2 completion (EventCard must exist)
|
||
- **Phase 7 (Polish)**: Depends on Phases 2–6 completion
|
||
|
||
### User Story Dependencies
|
||
|
||
- **US1 (P1)**: Depends only on Phase 1 — no other story dependencies
|
||
- **US2 (P2)**: Depends only on Phase 1 — independent of US1 but shares HomeView
|
||
- **US4 (P2)**: Depends on US1 (extends EventCard with past styling)
|
||
- **US3 (P3)**: Depends on US1 (extends EventList with delete flow)
|
||
- **US5 (P3)**: Depends on US1 (extends EventCard with role badge)
|
||
|
||
### Parallel Opportunities
|
||
|
||
- T003 + T004 + T005 can all run in parallel (different files)
|
||
- T006 + T007 can run in parallel (different test files)
|
||
- T008 can run in parallel with T006/T007 (component vs test files)
|
||
- US4, US5 can start in parallel once US1 is done (both extend EventCard independently)
|
||
|
||
---
|
||
|
||
## Implementation Strategy
|
||
|
||
### MVP First (User Story 1 Only)
|
||
|
||
1. Complete Phase 1: Setup composables
|
||
2. Complete Phase 2: US1 — EventCard, EventList, HomeView refactor
|
||
3. **STOP and VALIDATE**: Test the event list end-to-end
|
||
4. Deploy/demo if ready
|
||
|
||
### Incremental Delivery
|
||
|
||
1. Phase 1 → Composable layer ready
|
||
2. Phase 2 (US1) → Event list works → MVP!
|
||
3. Phase 3 (US2) → Empty state for new users
|
||
4. Phase 4 (US4) → Past events faded
|
||
5. Phase 5 (US3) → Remove events from list
|
||
6. Phase 6 (US5) → Role badges
|
||
7. Phase 7 → FAB, swipe, accessibility polish
|
||
|
||
---
|
||
|
||
## Notes
|
||
|
||
- [P] tasks = different files, no dependencies
|
||
- [Story] label maps task to specific user story for traceability
|
||
- This is a **frontend-only** feature — no backend changes needed
|
||
- All data comes from existing `useEventStorage` composable (localStorage)
|
||
- E2E tests consolidated in single file `home-events.spec.ts` with separate `describe` blocks per story
|