Persist dashboard layer, filter, style, and panel UI preferences in localStorage.

Hydrate saved toggles after client mount so SSR does not reset operator layer layouts on refresh, and store map style, filters, and section expand state alongside layer visibility.
This commit is contained in:
BigBodyCobain
2026-08-05 10:33:24 -06:00
parent 4c461a2ccd
commit f81cf88ecb
8 changed files with 422 additions and 87 deletions
@@ -0,0 +1,79 @@
import { afterEach, describe, expect, it } from 'vitest';
import {
DASHBOARD_PREFS_STORAGE_KEY,
LAYER_PREFERENCES_STORAGE_KEY,
clearActiveLayersPreference,
getDefaultActiveLayers,
getDefaultLayerSectionExpanded,
loadActiveFilters,
loadActiveLayers,
loadLayerSectionExpanded,
loadMapStyle,
mergeLayerSectionExpanded,
saveActiveFilters,
saveActiveLayers,
saveLayerSectionExpanded,
saveMapStyle,
} from '@/lib/layerPreferences';
describe('layerPreferences', () => {
afterEach(() => {
localStorage.removeItem(DASHBOARD_PREFS_STORAGE_KEY);
localStorage.removeItem(LAYER_PREFERENCES_STORAGE_KEY);
});
it('getDefaultActiveLayers returns a full boolean map', () => {
const defaults = getDefaultActiveLayers();
expect(defaults.flights).toBe(true);
expect(defaults.firms).toBe(false);
expect(Object.values(defaults).every((value) => typeof value === 'boolean')).toBe(true);
});
it('saveActiveLayers persists and loadActiveLayers restores', () => {
const customized = { ...getDefaultActiveLayers(), flights: false, cctv: true };
saveActiveLayers(customized);
expect(loadActiveLayers()).toEqual(customized);
});
it('migrates legacy sb_active_layers_v1 storage', () => {
localStorage.setItem(
LAYER_PREFERENCES_STORAGE_KEY,
JSON.stringify({ version: 1, layers: { flights: false } }),
);
expect(loadActiveLayers().flights).toBe(false);
});
it('persists map style without clobbering layers', () => {
saveActiveLayers({ ...getDefaultActiveLayers(), flights: false });
saveMapStyle('SATELLITE');
expect(loadMapStyle()).toBe('SATELLITE');
expect(loadActiveLayers().flights).toBe(false);
});
it('persists active filters', () => {
saveActiveFilters({ airline: ['UAL'], ship_type: ['Cargo'] });
expect(loadActiveFilters()).toEqual({ airline: ['UAL'], ship_type: ['Cargo'] });
});
it('persists layer section expand/collapse by stable id', () => {
const defaults = getDefaultLayerSectionExpanded();
saveLayerSectionExpanded({ ...defaults, aircraft: true, overlays: false });
expect(loadLayerSectionExpanded().aircraft).toBe(true);
expect(loadLayerSectionExpanded().overlays).toBe(false);
});
it('mergeLayerSectionExpanded keeps defaults for unknown section ids', () => {
const defaults = getDefaultLayerSectionExpanded();
const merged = mergeLayerSectionExpanded(defaults, { aircraft: true });
expect(merged.aircraft).toBe(true);
expect(merged.maritime).toBe(defaults.maritime);
});
it('clearActiveLayersPreference removes only layers from dashboard prefs', () => {
saveActiveLayers({ ...getDefaultActiveLayers(), flights: false });
saveMapStyle('SATELLITE');
clearActiveLayersPreference();
expect(loadActiveLayers()).toEqual(getDefaultActiveLayers());
expect(loadMapStyle()).toBe('SATELLITE');
});
});