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(EMPTY_PRODUCTS) const [loading, setLoading] = useState(false) const [error, setError] = useState(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 | 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 } }