diff --git a/backend/tests/test_sprint196_map_orthophoto_analysis.py b/backend/tests/test_sprint196_map_orthophoto_analysis.py index 97d1ab2b..778e34ca 100644 --- a/backend/tests/test_sprint196_map_orthophoto_analysis.py +++ b/backend/tests/test_sprint196_map_orthophoto_analysis.py @@ -318,6 +318,9 @@ def test_frontend_connects_map_selection_to_existing_detection_and_qa_flows() -> assert "prepareAndRunDetection(datasetId)" in hook_source assert "compareDetectionRunWithReference" in hook_source assert "compareDetectionRunWithReference(analysisRunId, referenceDatasetId, false)" in app_source + assert "vervoerregio|operationele grens" in app_source + assert "selectionBbox: mapSelectionBbox" in app_source + assert "Maak de rechthoek minstens 128 bij 128 meter groot." in hook_source assert "Herken gebouwen" in map_source assert "Officieel luchtbeeld, lokaal AI-model" in map_source diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index b9df1eb6..a26b5af2 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -472,7 +472,8 @@ function App(): JSX.Element { }) const mapOrthophotoAnalysis = useMapOrthophotoAnalysis({ selectedProjectId, - selectedAreaId: selectedMapAreaId, + selectedAreaId: areas.find((area) => /vervoerregio|operationele grens/i.test(area.name))?.id ?? selectedMapAreaId, + selectionBbox: mapSelectionBbox, datasets, loadProjectData, prepareAndRunDetection: (datasetId) => prepareAndRunDetection(datasetId, 'yolo-configured'), diff --git a/frontend/src/hooks/useMapOrthophotoAnalysis.ts b/frontend/src/hooks/useMapOrthophotoAnalysis.ts index 8da73d01..2c02f660 100644 --- a/frontend/src/hooks/useMapOrthophotoAnalysis.ts +++ b/frontend/src/hooks/useMapOrthophotoAnalysis.ts @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useEffect, useState } from 'react' import { datasetsApi } from '../services/api' import type { DatasetCreateResponse, @@ -20,6 +20,7 @@ export type MapOrthophotoAnalysisStage = interface MapOrthophotoAnalysisOptions { selectedProjectId: string | null selectedAreaId: string + selectionBbox: VectorSelectionBBox | null datasets: DatasetCreateResponse[] loadProjectData: (projectId: string) => Promise prepareAndRunDetection: (datasetId?: string) => Promise @@ -40,9 +41,30 @@ function findBuildingReference(datasets: DatasetCreateResponse[]): DatasetCreate ) ?? null } +function formatOrthophotoError(caught: unknown): string { + const code = caught instanceof Error ? (caught as Error & { code?: string }).code : undefined + if (code === 'ORTHOPHOTO_SELECTION_TOO_SMALL') { + return 'Maak de rechthoek minstens 128 bij 128 meter groot.' + } + if (code === 'ORTHOPHOTO_SELECTION_TOO_LARGE') { + return 'Maak de rechthoek maximaal 1.024 bij 1.024 meter groot.' + } + if (code === 'ORTHOPHOTO_SELECTION_OUTSIDE_AREA') { + return 'Teken de rechthoek binnen de ingeladen regio Kempen.' + } + if (code === 'ORTHOPHOTO_PROVIDER_UNAVAILABLE' || code === 'ORTHOPHOTO_PROVIDER_INVALID_RESPONSE') { + return 'De officiƫle luchtbeeldbron is tijdelijk niet bereikbaar. Probeer later opnieuw.' + } + if (code === 'ORTHOPHOTO_NOT_CONFIGURED') { + return 'Luchtbeelden ophalen is uitgeschakeld door de beheerder.' + } + return formatError(caught, 'De kaartgestuurde beeldanalyse is mislukt') +} + export function useMapOrthophotoAnalysis({ selectedProjectId, selectedAreaId, + selectionBbox, datasets, loadProjectData, prepareAndRunDetection, @@ -54,6 +76,13 @@ export function useMapOrthophotoAnalysis({ const [error, setError] = useState(null) const [lastResult, setLastResult] = useState(null) + useEffect(() => { + setStage('idle') + setStatus('') + setError(null) + setLastResult(null) + }, [selectionBbox?.min_x, selectionBbox?.min_y, selectionBbox?.max_x, selectionBbox?.max_y]) + const run = async (bbox: VectorSelectionBBox): Promise => { if (!selectedProjectId) { setError('De regionale werkruimte is nog niet geladen.') @@ -103,7 +132,7 @@ export function useMapOrthophotoAnalysis({ onAnalysisReady() return true } catch (caught) { - setError(formatError(caught, 'De kaartgestuurde beeldanalyse is mislukt')) + setError(formatOrthophotoError(caught)) setStatus('Analyse gestopt.') setStage('failed') return false