This commit is contained in:
Andras Schmelczer 2026-03-15 17:38:26 +00:00
parent 80c093b7ba
commit f72c43a9fa
101 changed files with 2168 additions and 1177 deletions

View file

@ -1,5 +1,12 @@
import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
import type { FeatureMeta, FeatureFilters, POICategoryGroup, ViewState, PostcodeGeometry, Property } from '../../types';
import type {
FeatureMeta,
FeatureFilters,
POICategoryGroup,
ViewState,
PostcodeGeometry,
Property,
} from '../../types';
import type { SearchedLocation } from './LocationSearch';
import type { Page } from '../ui/Header';
import Map from './Map';
@ -103,9 +110,7 @@ export default function MapPage({
const [poiPaneOpen, setPoiPaneOpen] = useState(false);
const [showBookmarkToast, setShowBookmarkToast] = useState(false);
const bookmarkToastDismissed = useRef(
localStorage.getItem('bookmark_toast_dismissed') === '1'
);
const bookmarkToastDismissed = useRef(localStorage.getItem('bookmark_toast_dismissed') === '1');
const handleSavePropertyWithToast = useCallback(
(property: Property) => {
@ -158,8 +163,7 @@ export default function MapPage({
max: entry.timeRange?.[1],
})),
};
const hasContext =
Object.keys(context.filters).length > 0 || context.travelTime.length > 0;
const hasContext = Object.keys(context.filters).length > 0 || context.travelTime.length > 0;
const result = await aiFilters.fetchAiFilters(query, hasContext ? context : undefined);
if (!result) return;
@ -174,7 +178,13 @@ export default function MapPage({
}));
travelTime.handleSetEntries(newEntries);
},
[aiFilters.fetchAiFilters, handleSetFilters, travelTime.handleSetEntries, travelTime.activeEntries, filters]
[
aiFilters.fetchAiFilters,
handleSetFilters,
travelTime.handleSetEntries,
travelTime.activeEntries,
filters,
]
);
const handleTravelTimeSetDestination = useCallback(
@ -246,7 +256,14 @@ export default function MapPage({
const pois = usePOIData(mapData.bounds, selectedPOICategories);
useUrlSync(mapData.currentView, filters, features, selectedPOICategories, selection.rightPaneTab, travelTime.entries);
useUrlSync(
mapData.currentView,
filters,
features,
selectedPOICategories,
selection.rightPaneTab,
travelTime.entries
);
useEffect(() => {
mapData.setInitialView(initialViewState);
@ -268,11 +285,18 @@ export default function MapPage({
if (!res.ok) throw new Error('Postcode not found');
return res.json();
})
.then((data: { postcode: string; latitude: number; longitude: number; geometry: PostcodeGeometry }) => {
mapFlyToRef.current?.(data.latitude, data.longitude, 16);
selection.handleLocationSearch(data.postcode, data.geometry);
if (isMobile) setMobileDrawerOpen(true);
})
.then(
(data: {
postcode: string;
latitude: number;
longitude: number;
geometry: PostcodeGeometry;
}) => {
mapFlyToRef.current?.(data.latitude, data.longitude, 16);
selection.handleLocationSearch(data.postcode, data.geometry);
if (isMobile) setMobileDrawerOpen(true);
}
)
.catch(() => {
// Silently fail — postcode might not exist
});
@ -397,7 +421,13 @@ export default function MapPage({
window.__screenshot_ready = true;
}
}
}, [screenshotMode, mapData.loading, mapData.data.length, mapData.postcodeData.length, mapData.usePostcodeView]);
}, [
screenshotMode,
mapData.loading,
mapData.data.length,
mapData.postcodeData.length,
mapData.usePostcodeView,
]);
const bookmarkToast = showBookmarkToast && (
<div className="fixed bottom-6 left-1/2 -translate-x-1/2 z-[60] flex items-center gap-3 px-4 py-3 rounded-lg bg-navy-900 text-white text-sm shadow-lg animate-fade-in">
@ -580,7 +610,9 @@ export default function MapPage({
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
<div className="flex items-center gap-2 bg-white/90 dark:bg-warm-800/90 px-4 py-2.5 rounded-lg shadow-lg pointer-events-auto">
<SpinnerIcon className="w-5 h-5 text-teal-600 dark:text-teal-400 animate-spin" />
<span className="text-sm font-medium text-warm-700 dark:text-warm-200">Loading...</span>
<span className="text-sm font-medium text-warm-700 dark:text-warm-200">
Loading...
</span>
</div>
</div>
)}
@ -641,9 +673,7 @@ export default function MapPage({
inline
/>
)}
<div className="flex-1 min-h-0">
{renderFilters()}
</div>
<div className="flex-1 min-h-0">{renderFilters()}</div>
</div>
{mobileDrawerOpen && selection.selectedHexagon && (
@ -746,7 +776,9 @@ export default function MapPage({
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
<div className="flex items-center gap-2 bg-white/90 dark:bg-warm-800/90 px-4 py-2.5 rounded-lg shadow-lg pointer-events-auto">
<SpinnerIcon className="w-5 h-5 text-teal-600 dark:text-teal-400 animate-spin" />
<span className="text-sm font-medium text-warm-700 dark:text-warm-200">Loading...</span>
<span className="text-sm font-medium text-warm-700 dark:text-warm-200">
Loading...
</span>
</div>
</div>
)}
@ -794,9 +826,7 @@ export default function MapPage({
</div>
<div className="flex-1 overflow-hidden">
{selection.rightPaneTab === 'properties'
? renderPropertiesPane()
: renderAreaPane()}
{selection.rightPaneTab === 'properties' ? renderPropertiesPane() : renderAreaPane()}
</div>
</div>
</div>