Display pois

This commit is contained in:
Andras Schmelczer 2026-01-26 22:02:17 +00:00
parent c157c2d5ec
commit 433fca64ad
6 changed files with 412 additions and 10 deletions

View file

@ -8,6 +8,9 @@ import type {
HexagonData,
ViewChangeParams,
ApiResponse,
POI,
POIResponse,
POICategoryGroup,
} from './types';
const DEBOUNCE_MS = 150;
@ -47,6 +50,12 @@ export default function App() {
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const abortControllerRef = useRef<AbortController | null>(null);
// POI state
const [pois, setPois] = useState<POI[]>([]);
const [selectedPOICategories, setSelectedPOICategories] = useState<Set<POICategoryGroup>>(new Set());
const poiDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const poiAbortControllerRef = useRef<AbortController | null>(null);
// Debounced fetch when dependencies change
useEffect(() => {
if (!bounds) return;
@ -95,6 +104,49 @@ export default function App() {
};
}, [filters, resolution, bounds]);
// Fetch POIs when bounds or selected categories change
useEffect(() => {
if (!bounds || selectedPOICategories.size === 0) {
setPois([]);
return;
}
if (poiDebounceRef.current) {
clearTimeout(poiDebounceRef.current);
}
poiDebounceRef.current = setTimeout(async () => {
if (poiAbortControllerRef.current) {
poiAbortControllerRef.current.abort();
}
poiAbortControllerRef.current = new AbortController();
try {
const boundsStr = `${bounds.south},${bounds.west},${bounds.north},${bounds.east}`;
const categoriesStr = Array.from(selectedPOICategories).join(',');
const params = new URLSearchParams({
categories: categoriesStr,
bounds: boundsStr,
});
const res = await fetch(`${getApiBaseUrl()}/api/pois?${params}`, {
signal: poiAbortControllerRef.current.signal,
});
const json: POIResponse = await res.json();
setPois(json.features || []);
} catch (err) {
if (err instanceof Error && err.name !== 'AbortError') {
console.error('Failed to fetch POIs:', err);
}
}
}, DEBOUNCE_MS);
return () => {
if (poiDebounceRef.current) {
clearTimeout(poiDebounceRef.current);
}
};
}, [bounds, selectedPOICategories]);
const handleViewChange = useCallback(
({ resolution: newRes, bounds: newBounds, zoom: newZoom }: ViewChangeParams) => {
setResolution(newRes);
@ -106,9 +158,15 @@ export default function App() {
return (
<div className="h-screen flex">
<Filters filters={filters} onChange={setFilters} zoom={zoom} />
<Filters
filters={filters}
onChange={setFilters}
zoom={zoom}
selectedPOICategories={selectedPOICategories}
onPOICategoriesChange={setSelectedPOICategories}
/>
<div className="flex-1 relative">
<Map data={data} onViewChange={handleViewChange} />
<Map data={data} pois={pois} onViewChange={handleViewChange} />
{loading && (
<div className="absolute top-4 right-4 bg-white px-3 py-1 rounded shadow">Loading...</div>
)}