feat: add auth-state awareness and graceful degradation

- Add /api/auth/whoami endpoint check on app load
- Store auth state in Zustand (authenticated, username, loaded)
- Hide Contacts tab when unauthenticated
- Gate fetchNearbyContacts calls on auth.authenticated
- Replace Save button with Log in affordance when unauthenticated
- Add Login/Logout buttons to panel header
- Prevent any /api/contacts/* requests from firing when unauthenticated

Public functionality (search, routing, place details) remains
fully functional for unauthenticated users.
This commit is contained in:
Matt 2026-04-27 01:26:05 +00:00
commit 0d4a807a05
29 changed files with 13091 additions and 317 deletions

View file

@ -1,7 +1,7 @@
import { useEffect, useRef, useCallback } from 'react'
import { useStore } from './store'
import { useTheme } from './hooks/useTheme'
import { requestRoute } from './api'
import { requestRoute, fetchAuthState } from './api'
import { decodePolyline } from './utils/decode'
import MapView from './components/MapView'
import Panel from './components/Panel'
@ -26,6 +26,12 @@ export default function App() {
const setRouteLoading = useStore((s) => s.setRouteLoading)
const setRouteError = useStore((s) => s.setRouteError)
const clearRoute = useStore((s) => s.clearRoute)
const setAuth = useStore((s) => s.setAuth)
// Initialize auth state on app load (single fetch, no polling)
useEffect(() => {
fetchAuthState().then(setAuth)
}, [setAuth])
// Fetch route when stops, mode, gpsOrigin, or geoPermission change (debounced 500ms)
useEffect(() => {