Skip to main content

Provider Nesting

The app uses deeply nested React context providers. Understanding the nesting order is important when adding new providers or consuming contexts.

Root Layout

The root layout (src/app/layout.tsx) wraps children in MaintenanceProvider.

App Layout

The (app) layout (src/app/(app)/layout.tsx) nests providers in this exact order:

LayoutProvider            → lockScroll / unlockScroll (document.body overflow control)
└─ PHProvider → PostHog init (capture_pageview: false, person_profiles: identified_only)
└─ SessionProvider → NextAuth session
└─ TrpcClientProvider → tRPC client + React Query QueryClientProvider
└─ UserLocationProvider → IP geolocation via tRPC (staleTime: Infinity)
└─ GMapsProvider → @vis.gl/react-google-maps APIProvider
└─ MapPlacesProvider → places dict, selectedPlace, markersLoaded, reloadPlaces
└─ SearchProvider → location, acsAttrs, categories; syncs URL ↔ state
└─ LoadingOverlayProvider → showOverlay(msg) / hideOverlay, z-100 modal

Map Layout

The map layout (src/app/(app)/map/layout.tsx) adds additional providers inside the app layout:

MobileProvider            → isMobile (≤1024px), activeSnapPoint, snapPoints
└─ PlacesQueryProvider → bounds-based tRPC search, 500ms debounce, PAGE_SIZE=20, pagination

Snap Points by Route

RouteSnap Points
/map (default)[0.14, 0.5, 1]
/map/place/[id][0.14, 0.6, 1]
/map/results['100px', 0.6, 1]

Important Notes

  • Any new provider must be inserted at the correct level based on its dependencies
  • Providers lower in the tree can access contexts from providers above them
  • The TrpcClientProvider must wrap anything that uses tRPC hooks
  • The SessionProvider must wrap anything that checks authentication
  • The GMapsProvider must wrap any Google Maps components