Skip to content

Hash Routing for Venue Navigation โ€‹

Date: 2026-03-22 Status: Complete

Problem โ€‹

The Dashboard component manages internal navigation via React state (view), but these transitions are invisible to the browser's history stack. On mobile, the back swipe pops the previous hash route (e.g. #/profile) instead of going back within the Dashboard (e.g. venue detail โ†’ places list).

Solution โ€‹

Promote Dashboard's internal view states to proper hash routes so the browser history stack tracks venue navigation correctly.

New Routes โ€‹

RouteViewReplaces
#/Places list (home)view === 'home'
#/?view=mapPlaces map viewviewMode === 'map'
#/venue/:idVenue detailview === 'venue'
#/venue/:id/lightLight lantern formview === 'form'
#/activeActive lantern screenview === 'active'
#/profile/privacyProfile privacy tabactiveTab === 'privacy' in ProfileSettings

Not routed (transient states, no back-button expectation):

  • success โ†’ redirects to #/active after confirmation
  • schedule-confirmation โ†’ stays as internal state (rare flow)

Implementation โ€‹

1. App.jsx โ€‹

  • Expand Dashboard rendering to match #/, #/venue/*, and #/active routes
  • Pass route prop to Dashboard
  • Add #/profile/privacy route that renders ProfileSettings with initialTab="privacy"

2. Dashboard.jsx โ€‹

  • Accept route prop, derive view and venueId from it
  • Replace setViewWithScrollSave(x) calls with window.location.hash = ... navigation
  • When route contains a venue ID, load the venue from local state or Firestore
  • Preserve scroll position save/restore logic by keying off the derived view

3. ProfileSettings.jsx โ€‹

  • Accept initialTab prop, default to 'profile'
  • Sync tab changes to hash: clicking Privacy tab navigates to #/profile/privacy

Key Considerations โ€‹

  • Venue loading on direct navigation: If user lands on #/venue/abc123 (e.g. from a shared link or back button), check venues array first, fall back to getVenue(id) from Firestore
  • Scroll restoration: Save scroll position before navigating away from home, restore on return โ€” same logic, just triggered by route changes instead of state changes
  • Lantern expiry redirect: When myLantern expires on active screen, navigate to #/ instead of calling setViewWithScrollSave('home')
  • Success screen: Goes directly to #/active (success is shown briefly in the flow)

Built with VitePress