From eb7ea50702274283b0e6c84004f27e15d3c4b39b Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Wed, 28 Oct 2026 22:55:27 +0700 Subject: [PATCH] feat: remember map view and add community first-run step --- src/components/FirstRunChecklist.tsx | 5 +++++ src/components/SpotMap.tsx | 6 +++--- src/pages/MapPage.tsx | 31 +++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/components/FirstRunChecklist.tsx b/src/components/FirstRunChecklist.tsx index c7a4de6..f4bf170 100644 --- a/src/components/FirstRunChecklist.tsx +++ b/src/components/FirstRunChecklist.tsx @@ -87,6 +87,11 @@ export function FirstRunChecklist() { {t('mapUi.firstRunWallet')} + + + ); diff --git a/src/components/SpotMap.tsx b/src/components/SpotMap.tsx index 935cfe1..2f98f4e 100644 --- a/src/components/SpotMap.tsx +++ b/src/components/SpotMap.tsx @@ -548,7 +548,7 @@ interface SpotMapProps { onSpotClick?: (spot: SkateSpot) => void; selectedSpot?: SkateSpot | null; onMapClick?: (lat: number, lng: number) => void; - onMapMove?: (center: { lat: number; lon: number }) => void; + onMapMove?: (center: { lat: number; lon: number; zoom?: number }) => void; enableClickToAdd?: boolean; className?: string; weatherEnabled?: boolean; @@ -977,7 +977,7 @@ export function SpotMap({ // Add moveend handler for BTC Map updates map.on('moveend', () => { const center = map.getCenter(); - onMapMoveRef.current?.({ lat: center.lat, lon: center.lng }); + onMapMoveRef.current?.({ lat: center.lat, lon: center.lng, zoom: map.getZoom() }); }); mapInstanceRef.current = map; @@ -1029,7 +1029,7 @@ export function SpotMap({ map.whenReady(() => { // Trigger initial map move event const center = map.getCenter(); - onMapMoveRef.current?.({ lat: center.lat, lon: center.lng }); + onMapMoveRef.current?.({ lat: center.lat, lon: center.lng, zoom: map.getZoom() }); }); }, 100); diff --git a/src/pages/MapPage.tsx b/src/pages/MapPage.tsx index 3f43a01..f76faa7 100644 --- a/src/pages/MapPage.tsx +++ b/src/pages/MapPage.tsx @@ -678,6 +678,27 @@ export default function MapPage() { // of the default world view. Resolved once at mount — a fresh fix or a manual // pan supersedes it. Makes the map feel "already yours" the moment it opens. const [initialView] = useState(() => { + // Restore the last map view first; a brand-new device falls back to the + // cached location, then to the world view. + try { + const raw = localStorage.getItem('skatespots:map-view'); + const saved = raw ? JSON.parse(raw) as { lat?: unknown; lon?: unknown; zoom?: unknown } : null; + if ( + saved && + typeof saved.lat === 'number' && Number.isFinite(saved.lat) && + typeof saved.lon === 'number' && Number.isFinite(saved.lon) && + typeof saved.zoom === 'number' && Number.isFinite(saved.zoom) + ) { + return { + center: [saved.lat, saved.lon] as [number, number], + zoom: Math.min(18, Math.max(1, saved.zoom)), + lat: saved.lat, + lon: saved.lon, + }; + } + } catch { + // fall through to the location/world default + } const cached = getLastLocation(); return cached ? { center: [cached.lat, cached.lng] as [number, number], zoom: 12, lat: cached.lat, lon: cached.lng } @@ -692,6 +713,14 @@ export default function MapPage() { lat: initialView.lat, lon: initialView.lon, }); + const handleMapMove = (center: { lat: number; lon: number; zoom?: number }) => { + setMapCenter({ lat: center.lat, lon: center.lon }); + try { + localStorage.setItem('skatespots:map-view', JSON.stringify(center)); + } catch { + // storage unavailable — map still works + } + }; // Near Me fly-to state const [flyTo, setFlyTo] = useState<{ lat: number; lng: number; zoom?: number } | null>(null); @@ -1751,7 +1780,7 @@ export default function MapPage() { selectedSpot={selectedSpot} onSpotClick={setSelectedSpot} onMapClick={handleMapClick} - onMapMove={setMapCenter} + onMapMove={handleMapMove} enableClickToAdd={!!user} className="h-full ss-map-floating-toolbar" weatherEnabled={weatherEnabled}