This commit is contained in:
Andras Schmelczer 2026-05-16 16:26:36 +01:00
parent e9a06417ad
commit 5e5d9f9a1c
16 changed files with 280 additions and 44 deletions

View file

@ -194,6 +194,82 @@ describe('useMapData', () => {
expect(result.current.colorRange?.[1]).toBeCloseTo(95);
});
it('does not use metadata min/max while slider preview colour data is loading', async () => {
const bounds = { south: 1, west: 1, north: 2, east: 2 };
const features: FeatureMeta[] = [
{
name: 'price',
type: 'numeric',
min: 0,
max: 100,
},
];
const filters = { price: [20, 80] as [number, number] };
const { result, rerender } = renderHook(
({
viewFeature,
activeFeature,
}: {
viewFeature: string | null;
activeFeature: string | null;
}) =>
useMapData({
filters,
features,
viewFeature,
activeFeature,
pinnedFeature: null,
travelTimeEntries: noTravelTimeEntries,
}),
{
initialProps: {
viewFeature: null as string | null,
activeFeature: null as string | null,
},
}
);
await act(async () => {
result.current.handleViewChange(viewChange(bounds));
});
await act(async () => {
vi.advanceTimersByTime(150);
});
await act(async () => {
requests[0].resolve(
response([
{ h3: 'density-low', count: 1, lat: 1.25, lon: 1.25 },
{ h3: 'density-high', count: 1, lat: 1.75, lon: 1.75 },
])
);
await flushPromises();
});
await act(async () => {
rerender({
viewFeature: 'price',
activeFeature: 'price',
});
await flushPromises();
});
expect(result.current.colorRange).toBeNull();
await act(async () => {
requests[1].resolve(
response([
{ h3: 'preview-low', count: 1, lat: 1.25, lon: 1.25, avg_price: 0 },
{ h3: 'preview-high', count: 1, lat: 1.75, lon: 1.75, avg_price: 100 },
])
);
await flushPromises();
});
expect(result.current.colorRange?.[0]).toBeCloseTo(5);
expect(result.current.colorRange?.[1]).toBeCloseTo(95);
});
it('does not reuse cached drag preview data when the drag request changes', async () => {
const bounds = { south: 1, west: 1, north: 2, east: 2 };
const features: FeatureMeta[] = [

View file

@ -516,9 +516,19 @@ export function useMapData({
return [0, meta.values.length - 1];
}
if (dataRange) return dataRange;
if (activeFeature && !hasMatchingDragData) return null;
if (loadedDataKey !== dataRequestKey) return null;
if (meta.min != null && meta.max != null) return [meta.min, meta.max];
return null;
}, [dataViewFeature, features, dataRange]);
}, [
activeFeature,
dataRequestKey,
dataRange,
dataViewFeature,
features,
hasMatchingDragData,
loadedDataKey,
]);
const isEyePreviewingPinnedFeature =
!activeFeature && dataViewFeature != null && dataViewFeature === pinnedDataViewFeature;
@ -642,13 +652,19 @@ export function useMapData({
[]
);
// Treat the map as loading whenever the rendered hexagons don't match the
// current request — covers the brief window between a slider release and
// the main fetch effect actually firing setLoading(true).
const isLoading =
loading || (bounds != null && !licenseRequired && loadedDataKey !== dataRequestKey);
return {
data,
committedHexagonData: rawData,
postcodeData: effectivePostcodeData,
resolution,
bounds,
loading,
loading: isLoading,
zoom,
currentView,
currentVisibleView,