59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
|
|
import type { NearbyStation, GeoPoint } from '../lib/nearby-stations';
|
|
import {
|
|
STATION_CATEGORIES,
|
|
selectNearbyStations,
|
|
stationSearchBounds,
|
|
} from '../lib/nearby-stations';
|
|
import type { POIResponse } from '../types';
|
|
import { apiUrl, assertOk, authHeaders, logNonAbortError } from '../lib/api';
|
|
|
|
function boundsParam(bounds: ReturnType<typeof stationSearchBounds>): string {
|
|
return `${bounds.south},${bounds.west},${bounds.north},${bounds.east}`;
|
|
}
|
|
|
|
export function useNearbyStations(origin: GeoPoint | null) {
|
|
const [stations, setStations] = useState<NearbyStation[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const lat = origin?.lat;
|
|
const lon = origin?.lon;
|
|
|
|
useEffect(() => {
|
|
if (lat == null || lon == null) {
|
|
setStations([]);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
const controller = new AbortController();
|
|
setStations([]);
|
|
setLoading(true);
|
|
|
|
const originPoint = { lat, lon };
|
|
const bounds = stationSearchBounds(originPoint);
|
|
const params = new URLSearchParams({
|
|
bounds: boundsParam(bounds),
|
|
categories: STATION_CATEGORIES.join(','),
|
|
});
|
|
|
|
fetch(apiUrl('pois', params), authHeaders({ signal: controller.signal }))
|
|
.then((response) => {
|
|
assertOk(response, 'nearby stations');
|
|
return response.json() as Promise<POIResponse>;
|
|
})
|
|
.then((json) => {
|
|
if (!controller.signal.aborted) {
|
|
setStations(selectNearbyStations(json.pois ?? [], originPoint));
|
|
}
|
|
})
|
|
.catch((error) => logNonAbortError('Failed to fetch nearby stations', error))
|
|
.finally(() => {
|
|
if (!controller.signal.aborted) setLoading(false);
|
|
});
|
|
|
|
return () => controller.abort();
|
|
}, [lat, lon]);
|
|
|
|
return { stations, loading };
|
|
}
|