Feature: Event Discovery Screen — Live Data

Branch: feat/event-discovery-live Date: 2026-03-18 Impact: Core screen rewritten from static mock data to fully live Supabase integration


What Changed

EventDiscoveryScreen was the most-visited screen in the app but ran entirely on hardcoded mock data. This feature replaces every placeholder with real data and navigation.


Before vs. After

AreaBeforeAfter
Widget typeStatefulWidgetConsumerStatefulWidget
Events3 hardcoded mock mapseventNotifierProvider (Supabase RPC)
Notification badgeHardcoded "3"unreadNotificationsCountProvider (hidden when 0, capped at 99+)
FiltersVisual only, no effectClient-side filter on real event list
Tapping a cardNo-opNavigates to /home/event-detail/:eventId
RSVP buttonShows snackbar onlyjoinEvent() / leaveEvent() → optimistic update
Share buttonNo-opShareService.shareEvent()
Create Event FABNo-opNavigates to /home/create-event
Notifications iconNo-opNavigates to /home/notifications
SearchStatic suggestion listsearchEvents() RPC, results via eventSearchResultsProvider
Empty / error statesNoneLoading spinner, error with retry, empty state
PaginationNoneLoad-more trigger at list bottom + pull-to-refresh

Architecture

State

The screen watches two providers:

final eventState = ref.watch(eventNotifierProvider);       // events, loading, error
final unreadCount = ref.watch(unreadNotificationsCountProvider); // badge

Filtering

Filters run client-side on the already-fetched list. The getEventsWithFriends RPC pre-loads social proof data (friends going count), so local filtering is instant and avoids extra network round-trips.

List<Event> _applyFilters(List<Event> events) {
  // filter by: today, weekend, free, friends, category
}

Pagination

The SliverChildBuilderDelegate uses childCount: events.length + 1. The extra item at index events.length triggers loadMoreEvents() when scrolled into view and shows a spinner while loading.

EventSearchDelegate now accepts a WidgetRef and wraps its results in a Consumer widget — the correct pattern for using Riverpod providers inside SearchDelegate, which is not a ConsumerWidget.


Files Changed

FileChange
lib/features/events/screens/event_discovery_screen.dartFull rewrite

Known Limitations

  • Category filter matches on event.category.name (enum name, lowercase). If events use display labels that differ from enum names, filtering may miss results — a dedicated category query param would be cleaner long-term.
  • isFeatured is currently set to true only for the first card when no filter is active. A proper isFeatured flag should come from the DB.