/** * Last-known-location cache. * ───────────────────────────────────────────────────────────────────────────── * Getting a fresh GPS fix takes time. To make the map feel instant we remember * the user's last successful location in localStorage and use it to: * 1. Open the map ALREADY centered on their area (optimistic initial view). * 2. Give "Near Me" something to fly to immediately while the fresh fix * resolves in the background. * * This is a coarse convenience cache, not a source of truth — a fresh fix always * supersedes it. We never store accuracy or timestamps beyond what's needed and * it lives only in this browser/app. */ export interface LastLocation { lat: number; lng: number; /** Epoch ms when this fix was captured. */ at: number; } const KEY = 'skatespots:last-location'; /** Consider a cached location "usable for centering" for 30 days. */ const MAX_AGE = 30 * 24 * 60 * 60 * 1000; /** Persist a successful location fix. Never throws. */ export function saveLastLocation(lat: number, lng: number): void { try { if ( typeof lat !== 'number' || typeof lng !== 'number' || Number.isNaN(lat) || Number.isNaN(lng) || (lat === 0 && lng === 0) ) { return; } const payload: LastLocation = { lat, lng, at: Date.now() }; localStorage.setItem(KEY, JSON.stringify(payload)); } catch { // ignore private-mode / quota failures } } /** * Read the cached location if present and not expired. Returns null otherwise. * Never throws. */ export function getLastLocation(): LastLocation | null { try { const raw = localStorage.getItem(KEY); if (!raw) return null; const parsed = JSON.parse(raw) as Partial; if ( typeof parsed?.lat !== 'number' || typeof parsed?.lng !== 'number' || typeof parsed?.at !== 'number' ) { return null; } if (Date.now() - parsed.at > MAX_AGE) return null; return { lat: parsed.lat, lng: parsed.lng, at: parsed.at }; } catch { return null; } }