fix: resolve 5 confirmed bugs from code review

- MapView.jsx: extract addBoundaryLayer function, use getComputedStyle
  for accent color (MapLibre rejects CSS vars in paint properties)
- PlaceCard.jsx: gate fetchNearbyContacts on auth.authenticated
- PlaceDetail.jsx: gate fetchNearbyContacts on auth.authenticated
- api.js: replace invalid timeout option with AbortSignal.timeout()
- RadialMenu.jsx: remove user-select from SVG style (Firefox rejects)
- Panel.jsx: add Cancel button for pending directions state
This commit is contained in:
Matt 2026-04-27 02:50:46 +00:00
commit a40f68fa26
39 changed files with 728 additions and 21085 deletions

View file

@ -25,7 +25,7 @@ export async function searchGeocode(query, limit = 6, signal) {
if (mapCenter?.zoom != null && Number.isFinite(mapCenter.zoom)) {
params.set('zoom', String(Math.round(mapCenter.zoom)))
}
const resp = await fetch(`${GEOCODE_URL}?${params}`, { signal, timeout: 5000 })
const resp = await fetch(`${GEOCODE_URL}?${params}`, { signal: signal ?? AbortSignal.timeout(5000) })
if (!resp.ok) throw new Error(`Geocode error: ${resp.status}`)
return resp.json()
}
@ -135,7 +135,7 @@ const REVERSE_URL = "/api/reverse"
export async function fetchReverse(lat, lon) {
try {
const params = new URLSearchParams({ lat: String(lat), lon: String(lon) })
const resp = await fetch(`${REVERSE_URL}?${params}`, { timeout: 5000 })
const resp = await fetch(`${REVERSE_URL}?${params}`, { signal: AbortSignal.timeout(5000) })
if (!resp.ok) return null
const data = await resp.json()
if (!data.results || data.results.length === 0) return null
@ -286,27 +286,27 @@ export async function fetchLandclass(lat, lon, signal) {
return null
}
}
// ── Auth API ──
/**
* Check authentication state via whoami endpoint.
* Uses redirect: manual to detect auth without triggering navigation.
* @returns {Promise<{authenticated: boolean, username: string|null}>}
*/
export async function fetchAuthState() {
try {
const resp = await fetch('/api/auth/whoami', { redirect: 'manual' })
// Redirect response means unauthenticated (Authentik SSO flow)
if (resp.type === 'opaqueredirect' || resp.status === 302) {
return { authenticated: false, username: null }
}
if (!resp.ok) {
return { authenticated: false, username: null }
}
return resp.json()
} catch {
return { authenticated: false, username: null }
}
}
// ── Auth API ──
/**
* Check authentication state via whoami endpoint.
* Uses redirect: manual to detect auth without triggering navigation.
* @returns {Promise<{authenticated: boolean, username: string|null}>}
*/
export async function fetchAuthState() {
try {
const resp = await fetch('/api/auth/whoami', { redirect: 'manual' })
// Redirect response means unauthenticated (Authentik SSO flow)
if (resp.type === 'opaqueredirect' || resp.status === 302) {
return { authenticated: false, username: null }
}
if (!resp.ok) {
return { authenticated: false, username: null }
}
return resp.json()
} catch {
return { authenticated: false, username: null }
}
}