Fun changes
Some checks failed
CI / Python (lint + test) (push) Failing after 3m38s
CI / Rust (lint + test) (push) Failing after 3m32s
CI / Frontend (lint + typecheck) (push) Failing after 4m12s
Build and publish Docker image / build-and-push (push) Failing after 4m48s

This commit is contained in:
Andras Schmelczer 2026-04-04 22:59:44 +01:00
parent cd778dd088
commit 349a6c1d53
60 changed files with 1260 additions and 2600 deletions

View file

@ -187,6 +187,16 @@ export default function MapPage({
handleToggleBest,
} = useTravelTime(initialTravelTime);
const mapFlyToRef = useRef<((lat: number, lng: number, zoom: number) => void) | null>(null);
const mapData = useMapData({
filters,
features,
viewFeature,
activeFeature,
travelTimeEntries: entries,
});
const handleAiFilterSubmit = useCallback(
async (query: string) => {
// Build context from current filters for conversational refinement
@ -213,8 +223,33 @@ export default function MapPage({
useBest: false,
}));
handleSetEntries(newEntries);
// Pan to the first travel time destination (mirroring handleTravelTimeSetDestination)
const firstTT = result.travelTimeFilters[0];
if (firstTT?.slug) {
try {
const res = await fetch(
apiUrl('travel-destinations', new URLSearchParams({ mode: firstTT.mode })),
authHeaders({})
);
if (res.ok) {
const data: { destinations: { slug: string; lat: number; lon: number }[] } =
await res.json();
const dest = data.destinations.find((d) => d.slug === firstTT.slug);
if (dest) {
mapFlyToRef.current?.(
dest.lat,
dest.lon,
mapData.currentView?.zoom ?? INITIAL_VIEW_STATE.zoom
);
}
}
} catch {
// Non-critical — filters are already applied, just skip the pan
}
}
},
[fetchAiFilters, handleSetFilters, handleSetEntries, activeEntries, filters]
[fetchAiFilters, handleSetFilters, handleSetEntries, activeEntries, filters, mapData.currentView?.zoom]
);
const handleClearAll = useCallback(() => {
@ -244,16 +279,6 @@ export default function MapPage({
const license = useLicense();
const mapFlyToRef = useRef<((lat: number, lng: number, zoom: number) => void) | null>(null);
const mapData = useMapData({
filters,
features,
viewFeature,
activeFeature,
travelTimeEntries: entries,
});
const filterCounts = useFilterCounts(filters, features, mapData.bounds, entries);
const handleTravelTimeSetDestination = useCallback(
@ -461,12 +486,7 @@ export default function MapPage({
if (mapData.licenseRequired) trackEvent('Upgrade Modal Shown');
}, [mapData.licenseRequired]);
const densityLabel = useMemo(() => {
const listingVal = filters['Listing status'] as string[] | undefined;
if (listingVal?.includes('For sale')) return t('mapLegend.propertiesForSale');
if (listingVal?.includes('For rent')) return t('mapLegend.propertiesForRent');
return t('mapLegend.historicalMatches');
}, [filters, t]);
const densityLabel = t('mapLegend.historicalMatches');
const mobileLegendMeta = useMemo(
() => (viewFeature ? features.find((f) => f.name === viewFeature) || null : null),
@ -652,7 +672,6 @@ export default function MapPage({
isLoggedIn={!!user}
onLoginRequired={onRegisterClick ?? (() => {})}
isLicensed={user?.subscription === 'licensed'}
isAdmin={user?.isAdmin === true}
onUpgradeClick={() => onNavigateTo('pricing')}
onResetTutorial={tutorial.resetTutorial}
filterImpacts={filterCounts.impacts}
@ -771,6 +790,7 @@ export default function MapPage({
onCancel={handleCancelPin}
mode="feature"
enumValues={mobileLegendMeta.type === 'enum' ? mobileLegendMeta.values : undefined}
featureName={mobileLegendMeta.name}
theme={theme}
inline
raw={mobileLegendMeta.raw}