| 73 | const statusMessage = state.status?.message ? ` · ${state.status.message}` : ""; |
| 74 | |
| 75 | const changeLocation = async (q: string) => { |
| 76 | if (!q.trim()) return; |
| 77 | setGeoBusy(true); |
| 78 | setGeoErr(null); |
| 79 | try { |
| 80 | const r = await fetch(`/api/geocode?q=${encodeURIComponent(q)}`); |
| 81 | if (!r.ok) { |
| 82 | setGeoErr(r.status === 404 ? `No match for “${q}”` : "Lookup failed"); |
| 83 | return; |
| 84 | } |
| 85 | const hit = (await r.json()) as { lat: number; lon: number; name: string }; |
| 86 | set({ centerLat: hit.lat, centerLon: hit.lon, locationName: hit.name }); |
| 87 | } catch { |
| 88 | setGeoErr("Lookup failed"); |
| 89 | } finally { |
| 90 | setGeoBusy(false); |
| 91 | } |
| 92 | }; |
| 93 | |
| 94 | // --- saved location profiles (favorite airports) --- |
| 95 | const genId = () => Date.now().toString(36) + Math.random().toString(36).slice(2, 7); |