Handle invalid GeoJSON in the editor

This commit is contained in:
Paul Chavard 2021-03-11 12:09:27 +01:00
parent c37feba8d1
commit 6f543d3770
2 changed files with 70 additions and 14 deletions

View file

@ -1,4 +1,10 @@
import React, { useState, useCallback, useRef, useMemo } from 'react'; import React, {
useState,
useCallback,
useRef,
useMemo,
useEffect
} from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import mapboxgl from 'mapbox-gl'; import mapboxgl from 'mapbox-gl';
import { GeoJSONLayer, ZoomControl } from 'react-mapbox-gl'; import { GeoJSONLayer, ZoomControl } from 'react-mapbox-gl';
@ -10,6 +16,7 @@ import { getJSON, ajax, fire } from '@utils';
import Mapbox from '../shared/mapbox/Mapbox'; import Mapbox from '../shared/mapbox/Mapbox';
import { getMapStyle } from '../shared/mapbox/styles'; import { getMapStyle } from '../shared/mapbox/styles';
import SwitchMapStyle from '../shared/mapbox/SwitchMapStyle'; import SwitchMapStyle from '../shared/mapbox/SwitchMapStyle';
import { FlashMessage } from '../shared/FlashMessage';
import ComboAdresseSearch from '../ComboAdresseSearch'; import ComboAdresseSearch from '../ComboAdresseSearch';
import { import {
@ -30,6 +37,7 @@ function MapEditor({ featureCollection, url, preview, options }) {
const drawControl = useRef(null); const drawControl = useRef(null);
const [currentMap, setCurrentMap] = useState(null); const [currentMap, setCurrentMap] = useState(null);
const [errorMessage, setErrorMessage] = useState();
const [style, setStyle] = useState('ortho'); const [style, setStyle] = useState('ortho');
const [coords, setCoords] = useState([1.7, 46.9]); const [coords, setCoords] = useState([1.7, 46.9]);
const [zoom, setZoom] = useState([5]); const [zoom, setZoom] = useState([5]);
@ -44,6 +52,11 @@ function MapEditor({ featureCollection, url, preview, options }) {
]); ]);
const hasCadastres = useMemo(() => options.layers.includes('cadastres')); const hasCadastres = useMemo(() => options.layers.includes('cadastres'));
useEffect(() => {
const timer = setTimeout(() => setErrorMessage(null), 5000);
return () => clearTimeout(timer);
}, [errorMessage]);
const translations = [ const translations = [
['.mapbox-gl-draw_line', 'Tracer une ligne'], ['.mapbox-gl-draw_line', 'Tracer une ligne'],
['.mapbox-gl-draw_polygon', 'Dessiner un polygone'], ['.mapbox-gl-draw_polygon', 'Dessiner un polygone'],
@ -118,21 +131,34 @@ function MapEditor({ featureCollection, url, preview, options }) {
} }
async function onDrawCreate({ features }) { async function onDrawCreate({ features }) {
for (const feature of features) { try {
const data = await getJSON(url, { feature }, 'post'); for (const feature of features) {
setFeatureId(feature.id, data.feature); const data = await getJSON(url, { feature }, 'post');
} setFeatureId(feature.id, data.feature);
}
updateFeaturesList(features); updateFeaturesList(features);
} catch {
setErrorMessage('Le polygone dessiné nest pas valide.');
}
} }
async function onDrawUpdate({ features }) { async function onDrawUpdate({ features }) {
for (const feature of features) { try {
let { id } = feature.properties; for (const feature of features) {
await getJSON(`${url}/${id}`, { feature }, 'patch'); const { id } = feature.properties;
} if (id) {
await getJSON(`${url}/${id}`, { feature }, 'patch');
} else {
const data = await getJSON(url, { feature }, 'post');
setFeatureId(feature.id, data.feature);
}
}
updateFeaturesList(features); updateFeaturesList(features);
} catch {
setErrorMessage('Le polygone dessiné nest pas valide.');
}
} }
async function onDrawDelete({ features }) { async function onDrawDelete({ features }) {
@ -152,8 +178,9 @@ function MapEditor({ featureCollection, url, preview, options }) {
); );
} }
const onFileImport = (e, inputId) => { const onFileImport = async (e, inputId) => {
readGeoFile(e.target.files[0]).then(async (featureCollection) => { try {
const featureCollection = await readGeoFile(e.target.files[0]);
const resultFeatureCollection = await getJSON( const resultFeatureCollection = await getJSON(
`${url}/import`, `${url}/import`,
featureCollection, featureCollection,
@ -188,7 +215,9 @@ function MapEditor({ featureCollection, url, preview, options }) {
updateFeaturesList(resultFeatureCollection.features); updateFeaturesList(resultFeatureCollection.features);
setImportInputs(setInputs); setImportInputs(setInputs);
setBbox(resultFeatureCollection.bbox); setBbox(resultFeatureCollection.bbox);
}); } catch {
setErrorMessage('Le fichier importé contient des polygones invalides.');
}
}; };
const addInputFile = (e) => { const addInputFile = (e) => {
@ -233,6 +262,9 @@ function MapEditor({ featureCollection, url, preview, options }) {
return ( return (
<> <>
{errorMessage && (
<FlashMessage message={errorMessage} level="alert" fixed={true} />
)}
<div> <div>
<p style={{ marginBottom: '20px' }}> <p style={{ marginBottom: '20px' }}>
Besoin d&apos;aide ?&nbsp; Besoin d&apos;aide ?&nbsp;

View file

@ -0,0 +1,24 @@
import React from 'react';
import { createPortal } from 'react-dom';
export function FlashMessage({ message, level, sticky, fixed }) {
return createPortal(
<div className="flash_message center">
<div className={flashClassName(level, sticky, fixed)}>{message}</div>
</div>,
document.getElementById('flash_messages')
);
}
function flashClassName(level, sticky = false, fixed = false) {
const className =
level == 'notice' ? ['alert', 'alert-success'] : ['alert', 'alert-danger'];
if (sticky) {
className.push('sticky');
}
if (fixed) {
className.push('alert-fixed');
}
return className.join(' ');
}