Add per-POI travel time filtering and fix heatmap color stops

Replace the single global max travel time filter with per-POI filters.
Each POI gets its own travel mode selector and max minutes input in the
filter panel. Listings must satisfy ALL active filters (AND logic).

Fix Mapbox "Input is not a number" error by ensuring color stops are
always strictly monotonic (guard min === max) and always set (even when
no valid metric values exist). Also filter Infinity values from the
color scale computation. Widen the filter panel from w-64 to w-80.
This commit is contained in:
Viktor Barzin 2026-02-08 16:02:46 +00:00
parent 81d31eaecf
commit 07d4fa5f84
No known key found for this signature in database
GPG key ID: 0EB088298288D958
5 changed files with 193 additions and 17 deletions

View file

@ -0,0 +1,41 @@
import type { PropertyFeature, POIDistanceInfo } from '@/types';
/**
* Build the flat property name used by the hexgrid heatmap to read
* travel-time values directly from feature.properties.
*/
export function poiMetricPropertyName(poiId: number, travelMode: string): string {
return `poi_travel_${poiId}_${travelMode}`;
}
/**
* Shallow-copy every feature and inject a flat numeric property
* (e.g. `poi_travel_7_TRANSIT = 1800`) so the heatmap can color by it.
*
* Features without matching POI distance data get `undefined` for that property,
* which the heatmap will skip (same as a listing with no sqm value).
*/
export function injectPoiMetricProperty(
features: PropertyFeature[],
poiId: number,
travelMode: string,
): PropertyFeature[] {
const propName = poiMetricPropertyName(poiId, travelMode);
return features.map((feature) => {
const distances: POIDistanceInfo[] | undefined = feature.properties.poi_distances;
const match = distances?.find(
(d) => d.poi_id === poiId && d.travel_mode === travelMode,
);
if (match === undefined) return feature;
return {
...feature,
properties: {
...feature.properties,
[propName]: match.duration_seconds,
},
};
});
}