This commit is contained in:
Andras Schmelczer 2026-05-31 13:17:11 +01:00
parent c995f12f8b
commit 8dc939d761
44 changed files with 3540 additions and 2159478 deletions

View file

@ -27,9 +27,11 @@ import { useFilterCounts } from '../../hooks/useFilterCounts';
import { trackEvent } from '../../lib/analytics';
import { INITIAL_VIEW_STATE, POSTCODE_ZOOM_THRESHOLD } from '../../lib/consts';
import type { OverlayId } from '../../lib/overlays';
import { CRIME_TYPE_VALUES } from '../../lib/crime-types';
import type { BasemapId } from '../../lib/basemaps';
import { useLicense } from '../../hooks/useLicense';
import { stateToParams } from '../../lib/url-state';
import { DEFAULT_COLOR_OPACITY, normalizeColorOpacity } from '../../lib/color-opacity';
import { groupFeaturesByCategory } from '../../lib/features';
import {
getActiveAmenityFilterFeatureNames,
@ -71,8 +73,6 @@ export type { ExportState } from './map-page/types';
type PendingFlyTo = { lat: number; lng: number; zoom: number };
const EMPTY_ACTUAL_LISTINGS: ActualListing[] = [];
declare const __DEV__: boolean;
export default function MapPage({
features,
poiCategoryGroups,
@ -80,7 +80,9 @@ export default function MapPage({
initialViewState,
initialPOICategories,
initialOverlays,
initialCrimeTypes,
initialBasemap = 'standard',
initialColorOpacity = DEFAULT_COLOR_OPACITY,
initialTab,
initialLoading,
theme,
@ -114,7 +116,13 @@ export default function MapPage({
const [activeOverlays, setActiveOverlays] = useState<Set<OverlayId>>(
() => new Set(initialOverlays ?? [])
);
const [crimeTypes, setCrimeTypes] = useState<Set<string>>(
() => new Set(initialCrimeTypes ?? CRIME_TYPE_VALUES)
);
const [basemap, setBasemap] = useState<BasemapId>(initialBasemap);
const [colorOpacity, setColorOpacity] = useState(() =>
normalizeColorOpacity(initialColorOpacity)
);
const [leftPaneWidth, leftPaneHandlers] = usePaneResize(384, 200, 0.45, 'left');
const [rightPaneWidth, rightPaneHandlers] = usePaneResize(384, 200, 0.45, 'right');
const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false);
@ -122,7 +130,10 @@ export default function MapPage({
const [poiPaneOpen, setPoiPaneOpen] = useState(false);
const [overlayPaneOpen, setOverlayPaneOpen] = useState(false);
const [currentLocation, setCurrentLocation] = useState<{ lat: number; lng: number } | null>(null);
const [devActualListingsEnabled, setDevActualListingsEnabled] = useState(true);
const [listingsToggleEnabled, setListingsToggleEnabled] = useState(true);
const [pendingInitialPostcode, setPendingInitialPostcode] = useState<string | null>(
initialPostcode ?? null
);
const {
filters,
@ -482,8 +493,12 @@ export default function MapPage({
[filters, features]
);
const actualListingsTravelParam = useMemo(() => buildTravelParam(entries), [entries]);
const actualListingsEnabled = !__DEV__ || devActualListingsEnabled;
const { listings: actualListings } = useActualListings(
// Listings are gated behind the per-user `can_see_listings` flag (off by
// default). Only users with the flag get the toggle button and the fetch;
// the backing API independently rejects anyone else with 403.
const canSeeListings = user?.canSeeListings ?? false;
const actualListingsEnabled = canSeeListings && listingsToggleEnabled;
const { listings: actualListings, loading: actualListingsLoading } = useActualListings(
actualListingsEnabled ? mapData.visibleBounds : null,
{
filterParam: actualListingsFilterParam,
@ -493,9 +508,13 @@ export default function MapPage({
);
const visibleActualListings = actualListingsEnabled ? actualListings : EMPTY_ACTUAL_LISTINGS;
const handleToggleActualListings = useCallback(() => {
if (!__DEV__) return;
setDevActualListingsEnabled((enabled) => !enabled);
}, []);
if (!canSeeListings) return;
setListingsToggleEnabled((enabled) => !enabled);
}, [canSeeListings]);
const selectedPostcodeParam =
selectedHexagon?.type === 'postcode'
? selectedHexagon.id
: (pendingInitialPostcode ?? undefined);
useUrlSync(
mapData.currentView,
@ -506,7 +525,10 @@ export default function MapPage({
entries,
shareCode,
activeOverlays,
basemap
basemap,
crimeTypes,
selectedPostcodeParam,
colorOpacity
);
useInitialMapPageView(mapData, initialViewState, initialTab, setRightPaneTab);
@ -520,6 +542,7 @@ export default function MapPage({
setMobileDrawerOpen(true);
consumePendingLocationSearchFlyTo();
},
onSettled: () => setPendingInitialPostcode(null),
});
useHorizontalSwipeNavigationGuard();
useMobileBackNavigationGuard(isMobile);
@ -581,16 +604,22 @@ export default function MapPage({
entries,
shareCode,
activeOverlays,
basemap
basemap,
crimeTypes,
selectedPostcodeParam,
colorOpacity
).toString(),
[
activeOverlays,
basemap,
crimeTypes,
colorOpacity,
entries,
features,
filters,
rightPaneTab,
selectedPOICategories,
selectedPostcodeParam,
shareCode,
shareAndSaveView,
]
@ -630,7 +659,9 @@ export default function MapPage({
ogMode={ogMode}
travelTimeEntries={entries}
activeOverlays={activeOverlays}
activeCrimeTypes={crimeTypes}
basemap={basemap}
colorOpacity={colorOpacity}
/>
);
}
@ -691,8 +722,12 @@ export default function MapPage({
<OverlayPane
selectedOverlays={activeOverlays}
onOverlaysChange={setActiveOverlays}
selectedCrimeTypes={crimeTypes}
onCrimeTypesChange={setCrimeTypes}
basemap={basemap}
onBasemapChange={setBasemap}
colorOpacity={colorOpacity}
onColorOpacityChange={setColorOpacity}
zoomedIn={overlaysZoomedIn}
onClose={() => setOverlayPaneOpen(false)}
/>
@ -827,7 +862,9 @@ export default function MapPage({
mapData={mapData}
pois={pois}
activeOverlays={activeOverlays}
activeCrimeTypes={crimeTypes}
basemap={basemap}
colorOpacity={colorOpacity}
mapViewFeature={mapViewFeature}
filterRange={filterRange}
viewSource={viewSource}
@ -847,7 +884,8 @@ export default function MapPage({
currentLocation={currentLocation}
actualListings={visibleActualListings}
actualListingsEnabled={actualListingsEnabled}
onToggleActualListings={__DEV__ ? handleToggleActualListings : undefined}
actualListingsLoading={actualListingsLoading}
onToggleActualListings={canSeeListings ? handleToggleActualListings : undefined}
travelTimeEntries={entries}
bottomScreenInset={mobileBottomSheetHeight}
onBottomSheetCoveredHeightChange={setMobileBottomSheetHeight}
@ -898,7 +936,9 @@ export default function MapPage({
mapData={mapData}
pois={pois}
activeOverlays={activeOverlays}
activeCrimeTypes={crimeTypes}
basemap={basemap}
colorOpacity={colorOpacity}
mapViewFeature={mapViewFeature}
filterRange={filterRange}
viewSource={viewSource}
@ -918,7 +958,8 @@ export default function MapPage({
currentLocation={currentLocation}
actualListings={visibleActualListings}
actualListingsEnabled={actualListingsEnabled}
onToggleActualListings={__DEV__ ? handleToggleActualListings : undefined}
actualListingsLoading={actualListingsLoading}
onToggleActualListings={canSeeListings ? handleToggleActualListings : undefined}
travelTimeEntries={entries}
densityLabel={densityLabel}
totalCount={hasActiveFilters ? filterCounts.total : undefined}