File size: 1,647 Bytes
cdbff92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import { useState, useEffect, useRef, useCallback } from 'react'

export default function useMapData(filters, viewport, zoom, mapMode, buildFilterParams) {
  const [geojson, setGeojson] = useState(null)
  const [loading, setLoading] = useState(true)
  const [totalInViewport, setTotalInViewport] = useState(0)
  const abortRef = useRef(null)
  const debounceRef = useRef(null)

  const fetchData = useCallback(async () => {
    if (abortRef.current) abortRef.current.abort()
    const controller = new AbortController()
    abortRef.current = controller
    setLoading(true)
    try {
      const params = new URLSearchParams()
      params.set('min_lng', viewport.min_lng)
      params.set('max_lng', viewport.max_lng)
      params.set('min_lat', viewport.min_lat)
      params.set('max_lat', viewport.max_lat)
      params.set('zoom', zoom)
      buildFilterParams(params)
      const endpoint = mapMode === 'heatmap' ? `/api/entities/geojson?${params}&max_features=5000` : `/api/entities/clusters?${params}`
      const resp = await fetch(endpoint, { signal: controller.signal })
      const data = await resp.json()
      setGeojson(data)
      setTotalInViewport(data.total_count || data.features?.length || 0)
    } catch (err) {
      if (err.name !== 'AbortError') console.error('Failed to fetch data:', err)
    }
    setLoading(false)
  }, [viewport, zoom, filters, mapMode, buildFilterParams])

  useEffect(() => {
    clearTimeout(debounceRef.current)
    debounceRef.current = setTimeout(fetchData, 200)
    return () => clearTimeout(debounceRef.current)
  }, [fetchData])

  return { geojson, loading, totalInViewport, fetchData }
}