Story 2.4: Attendee List Modal - Wireframe
Story: Epic 2, Story 2.4 - Current Event Landing Page (Extension)
Visual Wireframe
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Attendees (47) [โ Close] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โโโโโโโโโโโ FILTERS & SEARCH โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โโ
โ โ ๐ Search attendees... โโ
โ โ โโ
โ โ Filter: [All Companies โพ] [All Roles โพ] [โ] My Network โโ
โ โ โโ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ โโโโโโโโโโโ ATTENDEE LIST โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โโ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ [Photo] Sara Kim ๐ Connect โฎ โโโ
โ โ โ Senior Architect โโโ
โ โ โ Docker Inc. โโโ
โ โ โ ๐ Zรผrich โข ๐ฏ Speaker โโโ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โโ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ [Photo] Peter Mรผller โ Connected โฎ โโโ
โ โ โ DevOps Lead โโโ
โ โ โ TechCorp AG โโโ
โ โ โ ๐ Bern โข ๐ค Attendee โโโ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โโ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ [Photo] Anna Lopez ๐ Connect โฎ โโโ
โ โ โ Cloud Engineer โโโ
โ โ โ Swiss Re โโโ
โ โ โ ๐ Basel โข ๐ค Attendee โโโ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โโ
โ โ ... (47 attendees total) โโ
โ โ โโ
โ โ [Load More] โโ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ โโโโโโโโโโโ PRIVACY NOTICE โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โน๏ธ Only attendees who opted into networking are shown. โโ
โ โ Update your privacy settings [here]. โโ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ [Close] [My Profile] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Key Interactive Elements
- Search Box ๐: Real-time search filtering attendees by name, company, or location
- Company Filter Dropdown: Multi-select dropdown to filter attendees by company affiliation
- Role Filter Dropdown: Filter by attendee type (Speaker, Organizer, Partner, Attendee)
- My Network Toggle: Checkbox to show only connected/known attendees
- Connect Button ๐: Send connection request to attendee (authenticated users only)
- Connected Indicator โ: Shows existing connections with green checkmark
- More Options Menu โฎ: Access additional actions (View Profile, Message, Block)
- Attendee Card: Click to view full profile detail modal
- Load More Button: Pagination control to load next batch of attendees
- Privacy Settings Link: Navigate to user settings to manage networking visibility
- Close Button โ: Dismiss modal and return to Current Event Landing Page
- My Profile Button: Quick access to edit own attendee visibility
Functional Requirements Met
- FR6 (Current Event Prominence): Enhances the current event landing page by showing whoโs attending, increasing engagement and transparency
- FR14 (Personal Engagement Management): Enables attendees to manage networking connections and discover peers attending the event
- FR15 (Mobile-Optimized Experience): Modal design is fully responsive, works on mobile devices with touch-optimized cards and filters
- Privacy & GDPR Compliance: Only shows attendees who explicitly opted into networking visibility, with clear privacy controls
Technical Notes
UI Framework & Components
- Modal Component: Material-UI
Dialogwith full-screen mobile breakpoint - Search: Debounced input (300ms) with real-time filtering via API or local state
- Virtualization: React-window or react-virtuoso for rendering 100+ attendee cards efficiently
- Infinite Scroll: Intersection Observer API for โLoad Moreโ pagination trigger
- Skeleton Loading: Display skeleton cards during initial load and filtering
State Management
- Local State: Search query, selected filters, pagination cursor
- Server State (React Query): Attendee list cached with 5-minute stale time
- Optimistic Updates: Connection requests show immediate UI feedback before API confirmation
Responsive Design
- Mobile (<768px): Full-screen modal, stacked filters, card view
- Tablet (768-1024px): 80% viewport width modal, 2-column grid
- Desktop (>1024px): Fixed 700px width modal, single column list
Privacy & Security
- Opt-in Visibility: Default privacy setting is โhiddenโ - users must explicitly enable networking visibility
- Connection Requests: Stored separately from public attendee list; require mutual acceptance
- Block Feature: Users can hide specific attendees from their view
API Requirements
Initial Page Load APIs
-
GET /api/v1/events/{eventId}/attendees?include=company,connections
- Query params:
include=company,connections(consolidated resource expansion from Story 1.17)filter={"networkingOptIn":true}(only show users who enabled networking)limit=20(pagination)offset=0(pagination cursor)
- Returns: Array of attendee objects with expanded company and connection datajson
{ "attendees": [ { "userId": "uuid", "firstName": "Sara", "lastName": "Kim", "profilePhotoUrl": "https://cdn.batbern.ch/...", "jobTitle": "Senior Architect", "location": "Zรผrich", "role": "SPEAKER", "networkingOptIn": true, "company": { "id": "uuid", "name": "Docker Inc.", "logo": "https://cdn.batbern.ch/..." }, "connection": { "isConnected": false, "requestPending": false, "requestId": null } } ], "totalCount": 47, "hasMore": true, "nextOffset": 20 } - Used for: Populate attendee list with company and connection data in single API call, show total count in header, enable pagination
- Performance: Single API call replaces 3 separate calls (attendees + connections + settings)
- Query params:
-
GET /api/v1/attendees/me?include=settings
- Query params:
include=settings(consolidated Attendees API from Story 1.25) - Returns: Current userโs profile with privacy settingsjson
{ "userId": "uuid", "firstName": "string", "lastName": "string", "settings": { "networkingOptIn": true, "privacyLevel": "public" } } - Used for: Check if current user is visible to others, show privacy notice if opted out
- Query params:
User Action APIs
-
GET /api/v1/events/{eventId}/attendees?include=company,connections&filter={โฆ}
- Triggered by: User types in search box (debounced 300ms) or changes filters
- Query params (using consolidated filter syntax from Story 1.16):
include=company,connectionsfilter={"query":"sara","companies":["Docker Inc."],"roles":["SPEAKER"],"networkingOptIn":true}limit=20offset=0
- Response: Filtered attendee list (same schema as initial load)
- Used for: Real-time search filtering without separate search endpoint
- Performance: Uses same endpoint as initial load with different filter parameters
-
POST /api/v1/users/{userId}/connection-requests
- Triggered by: User clicks [๐ Connect] button
- Payload:json
{ "targetUserId": "uuid", "message": "Hi, looking forward to connecting at BATbern!", "eventId": "event-uuid" } - Response: Connection request confirmationjson
{ "requestId": "uuid", "status": "PENDING", "createdAt": "2025-05-01T10:00:00Z" } - Used for: Send connection request, show โRequest Sentโ button state
-
DELETE /api/v1/users/me/connection-requests/{requestId}
- Triggered by: User clicks โCancel Requestโ in more options menu (โฎ)
- Returns: 204 No Content
- Used for: Cancel pending connection request
-
GET /api/v1/events/{eventId}/attendees?include=company,connections&offset={cursor}
- Triggered by: User clicks [Load More] button or scrolls to bottom
- Query params:
offset={nextOffset},limit=20, same filters as current view - Returns: Next batch of attendees (append to existing list)
- Used for: Infinite scroll pagination
-
PATCH /api/v1/attendees/me
- Triggered by: User toggles networking opt-in via privacy settings link
- Payload:json
{ "settings": { "networkingOptIn": true } } - Response: Updated attendee profile
- Used for: Update privacy visibility using consolidated Attendees API (Story 1.25), refresh modal content
Navigation Map
Primary Navigation Actions
-
[โ Close] button (top-right) โ Dismiss modal
- Target: Current Event Landing Page (story-2.4-current-event-landing.md)
- Action: Close modal overlay, return focus to landing page
- Context: No state preserved
-
[Close] button (bottom-left) โ Dismiss modal
- Same as #1 (duplicate for accessibility and mobile UX)
-
[My Profile] button (bottom-right) โ Navigate to User Profile Settings
- Target: User Profile Screen (story-1.20-user-profile.md)
- Action: Open user profile in new modal or navigate to settings page
- Context: Opens to โPrivacy & Networkingโ tab if in settings
Secondary Navigation (Data Interactions)
-
Click Attendee Card โ Navigate to User Profile Preview Modal
- Target: User Profile Detail View (inline modal or full profile screen)
- Action: Show read-only profile with networking options
- Context: Pass
userId,eventIdfor contextualized view
-
[๐ Connect] button โ Send connection request (inline action, no navigation)
- No navigation - UI state change only
- Action: Button changes to โRequest Sentโ with disabled state
- Context: Show success toast notification
-
[โฎ More Options] menu โ Dropdown menu (inline, no navigation)
- Options:
- View Profile โ Navigate to full User Profile Detail View
- Send Message โ Opens messaging modal (future feature)
- Block User โ API call to block user (confirmation modal)
- Context: User-specific actions
- Options:
-
Privacy Settings [here] link โ Navigate to User Settings
- Target: User Settings Screen (story-5.2-user-settings.md)
- Action: Opens settings page with โPrivacy & Networkingโ tab active
- Context: Highlight
networkingOptIntoggle
Event-Driven Navigation
-
Connection Request Accepted (WebSocket/Polling) โ Update UI
- No navigation - real-time UI update
- Action: Change โRequest Sentโ button to โโ Connectedโ
- Context: Show notification toast โSara Kim accepted your connection requestโ
-
Search with No Results โ Show Empty State
- No navigation - inline empty state
- Action: Display โNo attendees found. Try different filters.โ
- Context: Preserve search query and filters for user to adjust
Error States & Redirects
-
Unauthenticated User โ Show Limited View or Login Prompt
- Target: Login Screen (story-1.2-login-screen.md)
- Condition: User not logged in, clicks [Connect] or views full list
- Action: Show modal overlay โSign in to connect with attendeesโ with [Login] CTA
- Context: Return to this modal after successful login
-
Privacy Disabled (User Opted Out) โ Show Privacy Banner
- No navigation - show inline banner at top of modal
- Message: โYouโre invisible to others. [Enable Networking] to appear in this list.โ
- Action: Click banner navigates to User Settings privacy tab
-
API Error (500, Network Failure) โ Show Error State
- No navigation - inline error message
- Action: Display โUnable to load attendees. [Retry]โ with retry button
- Context: Preserve userโs search and filter state for retry
Responsive Design Considerations
Mobile Layout Changes (<768px)
- Full-Screen Modal: Modal expands to 100% viewport height and width
- Filters Stack Vertically: Search box, company filter, role filter, and โMy Networkโ toggle stack in single column
- Attendee Cards: Full-width cards with left-aligned photo, single column layout
- Sticky Search: Search and filters stick to top of modal during scroll
- Bottom Sheet Actions: [Close] and [My Profile] buttons fixed to bottom as floating action buttons
- Touch Targets: All buttons and cards have minimum 44px tap target height
Tablet Layout Changes (768-1024px)
- 80% Viewport Width: Modal is 80% of screen width, max 600px
- 2-Column Grid (Optional): For landscape tablets, show 2-column card grid
- Filters Inline: Filters display in horizontal row instead of stacked
- Sidebar Possible: On landscape tablets, show filters in left sidebar panel
Mobile-Specific Interactions
- Swipe to Close: Swipe down gesture from top of modal closes it (native mobile pattern)
- Pull to Refresh: Swipe down on attendee list refreshes data
- Touch Feedback: Haptic feedback on connection request sent (if device supports)
- Card Swipe Actions: Swipe left on attendee card reveals quick actions (Connect, Block)
- Long Press Menu: Long press on attendee card shows context menu (alternative to โฎ button)
Accessibility Notes
-
ARIA Labels:
- Modal:
role="dialog"aria-labelledby="modal-title"aria-describedby="modal-description" - Close buttons:
aria-label="Close attendee list" - Connect buttons:
aria-label="Send connection request to Sara Kim" - More options:
aria-label="More options for Sara Kim"
- Modal:
-
Keyboard Navigation:
Tab: Navigate through search, filters, and attendee cardsEnter/Space: Activate buttons and open dropdownsEsc: Close modalArrow Keys: Navigate within dropdowns and card lists- Focus Trap: Focus remains within modal while open, returns to trigger element on close
-
Screen Reader Support:
- Total count announced: โ47 attendeesโ
- Filter changes announced: โFiltered to 12 attendees from Docker Inc.โ
- Connection status announced: โConnected with Peter Mรผllerโ
- Loading state announced: โLoading more attendeesโ
-
Color Contrast:
- All text meets WCAG 2.1 AA standards (4.5:1 ratio minimum)
- Connected checkmark uses green with sufficient contrast on white background
- Focus indicators are clearly visible (2px blue outline)
-
Reduced Motion: Respect
prefers-reduced-motionmedia query- Disable modal slide-in animation
- Disable smooth scrolling for pagination
- Reduce or remove transition effects
State Management
Local Component State
searchQuery: string- Current search input valueselectedCompanies: string[]- Selected companies for filteringselectedRoles: UserRole[]- Selected roles for filteringshowMyNetworkOnly: boolean- Toggle for โMy Networkโ filterattendees: Attendee[]- Current loaded attendee listisLoading: boolean- Loading state for initial load and paginationhasMore: boolean- Whether more attendees exist for paginationoffset: number- Current pagination offset
Global State (Zustand Store)
userConnections: string[]- List of user IDs the current user is connected withpendingConnectionRequests: string[]- List of user IDs with pending requestscurrentUser.networkingOptIn: boolean- Current userโs networking visibility setting
Server State (React Query)
-
eventAttendees - Cached attendee list with expanded company and connection data (consolidated API)
- Query Key:
['event-attendees', eventId, 'company,connections', filterParams] - Stale Time: 5 minutes (data is relatively static during event)
- Cache Time: 30 minutes
- Refetch on Focus: true (refresh when user returns to tab)
- Retry: 2 attempts with exponential backoff
- Single API call with
?include=company,connectionsreplaces 3 separate queries
- Query Key:
-
currentAttendeeSettings - Current userโs profile and settings
- Query Key:
['attendee', 'me', 'settings'] - Stale Time: 10 minutes
- Managed via consolidated Attendees API (Story 1.25)
- Query Key:
Real-Time Updates (Optional Enhancement)
- WebSocket Connection: Subscribe to connection request updates
- Event:
CONNECTION_REQUEST_ACCEPTEDโ Update UI to show โโ Connectedโ - Event:
CONNECTION_REQUEST_REJECTEDโ Revert button to โ๐ Connectโ
- Event:
- Polling Fallback: Poll
/api/v1/users/me/connectionsevery 30 seconds if WebSocket unavailable
Form Validation Rules
Field-Level Validations
This screen contains search and filter inputs but no traditional form submission. Validation is minimal:
-
Search Query:
- Min length: 0 (empty allowed for โshow allโ)
- Max length: 100 characters
- Sanitization: Strip HTML tags, trim whitespace
- Debounced: 300ms delay before triggering API call
-
Company Filter:
- Multi-select allowed
- No validation required (dropdown from predefined list)
-
Role Filter:
- Multi-select allowed
- No validation required (dropdown from enum: ORGANIZER, SPEAKER, PARTNER, ATTENDEE)
Form-Level Validations
No form-level validations required. This is a read-only list with filtering capabilities, not a data submission form.
Edge Cases & Error Handling
Empty States
-
No Attendees Registered:
- Show message: โNo attendees yet. Be the first to register!โ
- Display [Register Now] CTA button
-
All Attendees Opted Out of Networking:
- Show message: โNo attendees have enabled networking visibility yet.โ
- Display privacy explanation and [Learn More] link
-
Search Returns No Results:
- Show message: โNo attendees found for โqueryโ. Try different filters.โ
- Display [Clear Search] button to reset
-
User Not Registered for Event:
- Show banner: โRegister for the event to connect with attendees. [Register]โ
- Display limited view (first 5 attendees only)
Loading States
- Initial Load: Display 5 skeleton attendee cards with pulsing animation
- Pagination Load: Show spinner below last attendee card with โLoading moreโฆโ
- Search Filtering: Show loading overlay on attendee list with semi-transparent background
Error States
-
API Failure (500 Error):
- Show error message: โUnable to load attendees. Please try again.โ
- Display [Retry] button that re-triggers API call
- Log error to monitoring service (Sentry)
-
Network Timeout:
- Show message: โRequest timed out. Check your connection and [Retry].โ
- Retry automatically after 5 seconds (show countdown)
-
Unauthorized (401):
- Redirect to login screen with return URL
- Show toast: โPlease sign in to view attendees.โ
-
Forbidden (403 - User Banned):
- Show message: โYou donโt have permission to view attendees.โ
- Disable modal interaction
Permission & Privacy Cases
-
Current User Opted Out:
- Show prominent banner at top: โYouโre invisible to other attendees. [Enable Networking]โ
- Still allow user to browse attendee list
-
Blocked Users:
- Donโt display blocked users in attendee list
- No indication that users have been filtered out (privacy protection)
-
Connection Request Limit Exceeded:
- Disable [Connect] button when user reaches rate limit (e.g., 20 requests/hour)
- Show tooltip: โYouโve reached the connection request limit. Try again in 1 hour.โ
Edge Case: Event Date Passed
- Post-Event Access:
- Show historical attendee list (read-only)
- Disable [Connect] button: โEvent has ended. View profiles only.โ
- Remove โMy Networkโ filter (less relevant post-event)
Change Log
| Date | Version | Description | Author |
|---|---|---|---|
| 2025-10-04 | 1.0 | Initial wireframe creation | Sally (UX) |
| 2025-10-04 | 1.1 | Updated to use consolidated APIs from Stories 1.16, 1.17, 1.25: single attendees endpoint with ?include=company,connections (reduced 3 API calls to 1), filter syntax for search, settings management via PATCH /api/v1/attendees/me | Winston (Architect) |
Review Notes
Stakeholder Feedback
No feedback yet - awaiting review
Design Iterations
Initial design based on Current Event Landing Page extension and networking requirements
Open Questions
-
Connection Request Workflow: Should connection requests be event-specific or platform-wide (follow across all events)?
- Recommendation: Platform-wide connections (like LinkedIn) to build lasting community network
-
Privacy Defaults: Should networking opt-in be enabled by default for new users?
- Recommendation: Default to
false(GDPR conservative approach), prompt users during first event registration
- Recommendation: Default to
-
Messaging Feature: Should connected users be able to message each other directly?
- Recommendation: Phase 2 feature - start with connection requests only, add messaging later
-
Speaker Highlighting: Should speakers/organizers have special badges or highlighted cards?
- Recommendation: Yes - use role badge (๐ฏ Speaker, ๐ฅ Organizer) to help attendees identify key people
-
Company Logo Display: Should attendee cards show company logos instead of/in addition to company names?
- Recommendation: Show company logo if available (20px thumbnail), fallback to company name
Implementation Priority: ๐ข LOW - Nice-to-have networking feature for enhanced attendee engagement. Not blocking MVP launch.
Dependencies:
- User authentication (Story 1.2)
- Event registration system (Story 2.4)
- User profile management (Story 1.20)
- Privacy settings (Story 5.2)
Related Screens:
- Current Event Landing Page (story-2.4-current-event-landing.md)
- User Profile (story-1.20-user-profile.md)
- User Settings (story-5.2-user-settings.md)