From 1a5487f0f72807308d4bb6eb1e24a7d52328ee6d Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Wed, 25 Mar 2026 01:08:33 +0200 Subject: [PATCH] fix: zoom no longer resets after manual pan/zoom (fitBounds once per siruta) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fitBounds effect was re-triggered every time mapReady toggled (which happened frequently due to the source-checking polling interval). Now uses boundsFittedForSirutaRef to ensure fitBounds runs only ONCE per siruta selection — changing UAT still zooms correctly, but manual zoom/pan is preserved afterwards. Fixed in both ParcelSync Harta tab and Portal map. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/(portal)/portal/page.tsx | 11 ++++++++--- src/modules/parcel-sync/components/tabs/map-tab.tsx | 12 +++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/app/(portal)/portal/page.tsx b/src/app/(portal)/portal/page.tsx index bd1b91d..e6349fb 100644 --- a/src/app/(portal)/portal/page.tsx +++ b/src/app/(portal)/portal/page.tsx @@ -1161,6 +1161,7 @@ function HartaContent() { // Bounds state const boundsRef = useRef<[number, number, number, number] | null>(null); const appliedSirutaRef = useRef(""); + const boundsFittedForSirutaRef = useRef(""); const prevBoundsSirutaRef = useRef(""); // Layer visibility: show terenuri + cladiri @@ -1230,22 +1231,26 @@ function HartaContent() { if (data?.bounds) { const [[minLng, minLat], [maxLng, maxLat]] = data.bounds; boundsRef.current = [minLng, minLat, maxLng, maxLat]; + boundsFittedForSirutaRef.current = ""; const map = asMap(mapHandleRef.current); if (map) { map.fitBounds([minLng, minLat, maxLng, maxLat], { padding: 40, duration: 1500 }); + boundsFittedForSirutaRef.current = selectedSiruta; } } }) .catch(() => {}); }, [selectedSiruta]); - // When map becomes ready, fitBounds and apply filter + // When map becomes ready, fitBounds ONCE per siruta useEffect(() => { - if (!mapReady || !boundsRef.current) return; + if (!mapReady || !boundsRef.current || !selectedSiruta) return; + if (boundsFittedForSirutaRef.current === selectedSiruta) return; const map = asMap(mapHandleRef.current); if (!map) return; map.fitBounds(boundsRef.current, { padding: 40, duration: 1500 }); - }, [mapReady]); + boundsFittedForSirutaRef.current = selectedSiruta; + }, [mapReady, selectedSiruta]); // Apply siruta filter to layers useEffect(() => { diff --git a/src/modules/parcel-sync/components/tabs/map-tab.tsx b/src/modules/parcel-sync/components/tabs/map-tab.tsx index 8b5c2aa..1656f1d 100644 --- a/src/modules/parcel-sync/components/tabs/map-tab.tsx +++ b/src/modules/parcel-sync/components/tabs/map-tab.tsx @@ -102,6 +102,7 @@ export function MapTab({ siruta, sirutaValid, sessionConnected, syncLocalCount, const appliedSirutaRef = useRef(""); const boundsRef = useRef<[number, number, number, number] | null>(null); const prevCheckSirutaRef = useRef(""); + const boundsFittedForSirutaRef = useRef(""); /* Boundary check results */ const [mismatchSummary, setMismatchSummary] = useState<{ @@ -164,12 +165,14 @@ export function MapTab({ siruta, sirutaValid, sessionConnected, syncLocalCount, if (data?.bounds) { const [[minLng, minLat], [maxLng, maxLat]] = data.bounds; boundsRef.current = [minLng, minLat, maxLng, maxLat]; + boundsFittedForSirutaRef.current = ""; // reset — need to fit for new siruta const map = asMap(mapHandleRef.current); if (map) { map.fitBounds([minLng, minLat, maxLng, maxLat], { padding: 40, duration: 1500, }); + boundsFittedForSirutaRef.current = siruta; } } }, @@ -178,13 +181,16 @@ export function MapTab({ siruta, sirutaValid, sessionConnected, syncLocalCount, .finally(() => setBoundsLoading(false)); }, [siruta, sirutaValid]); - /* ── When map becomes ready, fitBounds if we have bounds ───── */ + /* ── When map becomes ready, fitBounds ONCE per siruta ──────── */ useEffect(() => { - if (!mapReady || !boundsRef.current) return; + if (!mapReady || !boundsRef.current || !siruta) return; + // Only fit bounds once per siruta — don't reset zoom on basemap switch or re-render + if (boundsFittedForSirutaRef.current === siruta) return; const map = asMap(mapHandleRef.current); if (!map) return; map.fitBounds(boundsRef.current, { padding: 40, duration: 1500 }); - }, [mapReady]); + boundsFittedForSirutaRef.current = siruta; + }, [mapReady, siruta]); /* ── Apply siruta filter + enrichment overlay ──────────────── */ useEffect(() => {