Handle invalid GeoJSON in the editor
This commit is contained in:
parent
c37feba8d1
commit
6f543d3770
2 changed files with 70 additions and 14 deletions
|
@ -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é n’est 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é n’est 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'aide ?
|
Besoin d'aide ?
|
||||||
|
|
24
app/javascript/components/shared/FlashMessage.jsx
Normal file
24
app/javascript/components/shared/FlashMessage.jsx
Normal 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(' ');
|
||||||
|
}
|
Loading…
Reference in a new issue