import { useEffect, useRef } from 'react'; import { useLocation, useNavigationType } from 'react-router-dom'; const KEY = 'skatespots:scroll-positions'; const MAX = 80; interface SavedPosition { path: string; y: number; at: number; } function readPositions(): Record { try { const raw = sessionStorage.getItem(KEY); if (!raw) return {}; const parsed = JSON.parse(raw) as unknown; return parsed && typeof parsed === 'object' ? parsed as Record : {}; } catch { return {}; } } function writePositions(positions: Record): void { try { const entries = Object.entries(positions) .sort(([, a], [, b]) => b.at - a.at) .slice(0, MAX); sessionStorage.setItem(KEY, JSON.stringify(Object.fromEntries(entries))); } catch { // storage may be unavailable } } /** * Scroll behaviour: * - new navigation starts at the top; * - browser Back/Forward restores the saved position for that history entry; * - query/tab changes on the same page keep the current scroll. */ export function ScrollToTop() { const location = useLocation(); const navigationType = useNavigationType(); const previousPath = useRef(location.pathname); const raf = useRef(null); useEffect(() => { const positions = readPositions(); const pathChanged = previousPath.current !== location.pathname; previousPath.current = location.pathname; if (!pathChanged) return; if (navigationType === 'POP') { const saved = positions[location.key]?.y ?? 0; requestAnimationFrame(() => window.scrollTo(0, saved)); } else { window.scrollTo(0, 0); } }, [location.key, location.pathname, navigationType]); useEffect(() => { const save = () => { if (raf.current !== null) return; raf.current = window.requestAnimationFrame(() => { raf.current = null; const positions = readPositions(); positions[location.key] = { path: location.pathname, y: window.scrollY, at: Date.now(), }; writePositions(positions); }); }; window.addEventListener('scroll', save, { passive: true }); return () => { window.removeEventListener('scroll', save); if (raf.current !== null) window.cancelAnimationFrame(raf.current); raf.current = null; }; }, [location.key, location.pathname]); return null; }