Files
geointel/frontend/src/hooks/useOfficialMapProducts.ts
T
Codex cee6cd05ae
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s
feat: complete Wallonia land cover and terrain sources
2026-07-22 06:28:46 +02:00

162 lines
4.7 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react'
import { datasetsApi, externalApi } from '../services/api'
import { formatError } from '../lib/formatError'
import type {
BathymetrySourceRead,
CoverageResolveResponse,
DhmvProductRead,
SpwTerrainProductRead,
FloodHazardProductRead,
GrbProductRead,
OfficialVectorProductRead,
ThematicRasterProductRead,
VectorSelectionBBox,
} from '../types'
export interface OfficialMapProducts {
thematic: ThematicRasterProductRead[]
walous: ThematicRasterProductRead[]
dhmv: DhmvProductRead[]
spwTerrain: SpwTerrainProductRead[]
floodHazard: FloodHazardProductRead[]
grb: GrbProductRead[]
officialVector: OfficialVectorProductRead[]
bathymetry: BathymetrySourceRead[]
}
const EMPTY_PRODUCTS: OfficialMapProducts = {
thematic: [],
walous: [],
dhmv: [],
spwTerrain: [],
floodHazard: [],
grb: [],
officialVector: [],
bathymetry: [],
}
export function useOfficialMapProducts(selectedProjectId: string | null) {
const [products, setProducts] = useState<OfficialMapProducts>(EMPTY_PRODUCTS)
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
let cancelled = false
if (!selectedProjectId) {
setProducts(EMPTY_PRODUCTS)
setLoading(false)
setError(null)
return () => {
cancelled = true
}
}
setLoading(true)
setError(null)
void Promise.all([
datasetsApi.listThematicRasterProducts(selectedProjectId),
datasetsApi.listWalousProducts(selectedProjectId),
datasetsApi.listDhmvProducts(selectedProjectId),
datasetsApi.listSpwTerrainProducts(selectedProjectId),
datasetsApi.listFloodHazardProducts(selectedProjectId),
datasetsApi.listGrbProducts(selectedProjectId),
datasetsApi.listOfficialVectorProducts(selectedProjectId),
datasetsApi.listBathymetrySources(selectedProjectId),
])
.then(([thematic, walous, dhmv, spwTerrain, floodHazard, grb, officialVector, bathymetry]) => {
if (!cancelled) {
setProducts({
thematic: thematic.items,
walous: walous.items,
dhmv: dhmv.items,
spwTerrain: spwTerrain.items,
floodHazard: floodHazard.items,
grb: grb.items,
officialVector: officialVector.items,
bathymetry: bathymetry.items,
})
}
})
.catch((requestError) => {
if (!cancelled) {
setProducts(EMPTY_PRODUCTS)
setError(formatError(requestError, 'De officiële regionale kaartcatalogi konden niet worden geladen.'))
}
})
.finally(() => {
if (!cancelled) {
setLoading(false)
}
})
return () => {
cancelled = true
}
}, [selectedProjectId])
const resolveCoverage = useCallback(
async (bbox: { minx: number; miny: number; maxx: number; maxy: number }) => {
if (!selectedProjectId) {
setError('Selecteer eerst een werkruimte.')
return null
}
try {
const coverage = await externalApi.resolveCoverage({
projectId: selectedProjectId,
bbox,
})
setError(null)
return coverage
} catch (requestError) {
setError(formatError(requestError, 'De regionale databronnen konden niet veilig worden bepaald.'))
return null
}
},
[selectedProjectId],
)
const resolveCoveragePartitions = useCallback(
async (bboxes: VectorSelectionBBox[]): Promise<Array<{
bbox: VectorSelectionBBox
coverage: CoverageResolveResponse
}> | null> => {
if (!selectedProjectId) {
setError('Selecteer eerst een werkruimte.')
return null
}
try {
const resolved: Array<{
bbox: VectorSelectionBBox
coverage: CoverageResolveResponse
}> = []
for (let offset = 0; offset < bboxes.length; offset += 4) {
const batch = bboxes.slice(offset, offset + 4)
resolved.push(...await Promise.all(batch.map(async (bbox) => ({
bbox,
coverage: await externalApi.resolveCoverage({
projectId: selectedProjectId,
bbox: {
minx: bbox.min_x,
miny: bbox.min_y,
maxx: bbox.max_x,
maxy: bbox.max_y,
},
}),
}))))
}
setError(null)
return resolved
} catch (requestError) {
setError(formatError(
requestError,
'De regionale dekking kon niet voor alle bronpartities worden bepaald.',
))
return null
}
},
[selectedProjectId],
)
return { products, loading, error, resolveCoverage, resolveCoveragePartitions }
}