import React, { useState } from 'react'; import PropTypes from 'prop-types'; import ReactMapboxGl, { ZoomControl } from 'react-mapbox-gl'; import DrawControl from 'react-mapbox-gl-draw'; import { CursorClickIcon, PlusIcon, LocationMarkerIcon } from '@heroicons/react/outline'; import CoordinateInput from 'react-coordinate-input'; import { fire } from '@utils'; import VisuallyHidden from '@reach/visually-hidden'; import { useId } from '@reach/auto-id'; import 'mapbox-gl/dist/mapbox-gl.css'; import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'; import MapStyleControl, { useMapStyle } from '../shared/mapbox/MapStyleControl'; import { FlashMessage } from '../shared/FlashMessage'; import ComboAdresseSearch from '../ComboAdresseSearch'; import { useMapboxEditor } from './useMapboxEditor'; const Mapbox = ReactMapboxGl({}); function MapEditor({ featureCollection, url, options, preview }) { const [cadastreEnabled, setCadastreEnabled] = useState(false); const [coords, setCoords] = useState([1.7, 46.9]); const [zoom, setZoom] = useState([5]); const { isSupported, error, inputs, onLoad, onStyleChange, onFileChange, drawRef, createFeatures, updateFeatures, deleteFeatures, addInputFile, removeInputFile } = useMapboxEditor(featureCollection, { url, enabled: !preview, cadastreEnabled }); const { style, layers, setStyle, setLayerEnabled, setLayerOpacity } = useMapStyle(options.layers, { onStyleChange, cadastreEnabled }); if (!isSupported) { return ( <p> Nous ne pouvons pas afficher notre éditeur de carte car il est imcompatible avec votre navigateur. Nous vous conseillons de le mettre à jour ou utiliser les dernières versions de Chrome, Firefox ou Safari </p> ); } return ( <> {error && <FlashMessage message={error} level="alert" fixed={true} />} <div> <p style={{ marginBottom: '20px' }}> Besoin d'aide ? <a href="https://doc.demarches-simplifiees.fr/pour-aller-plus-loin/cartographie" target="_blank" rel="noreferrer" > consulter les tutoriels video </a> </p> </div> <div className="file-import" style={{ marginBottom: '10px' }}> <button className="button send primary" onClick={addInputFile}> Ajouter un fichier GPX ou KML </button> <div> {inputs.map((input) => ( <div key={input.id}> <input title="Choisir un fichier gpx ou kml" style={{ marginTop: '15px' }} id={input.id} type="file" accept=".gpx, .kml" disabled={input.disabled} onChange={(e) => onFileChange(e, input.id)} /> {input.hasValue && ( <span title="Supprimer le fichier" className="icon refuse" style={{ cursor: 'pointer' }} onClick={(e) => removeInputFile(e, input.id)} ></span> )} </div> ))} </div> </div> <div style={{ marginBottom: '10px' }} > <ComboAdresseSearch className="no-margin" placeholder="Rechercher une adresse : saisissez au moins 2 caractères" allowInputValues={false} onChange={(_, { geometry: { coordinates } }) => { setCoords(coordinates); setZoom([17]); }} /> </div> <Mapbox onStyleLoad={(map) => onLoad(map)} center={coords} zoom={zoom} style={style} containerStyle={{ height: '500px' }} > {!cadastreEnabled && ( <DrawControl ref={drawRef} onDrawCreate={createFeatures} onDrawUpdate={updateFeatures} onDrawDelete={deleteFeatures} displayControlsDefault={false} controls={{ point: true, line_string: true, polygon: true, trash: true }} /> )} <MapStyleControl style={style.id} layers={layers} setStyle={setStyle} setLayerEnabled={setLayerEnabled} setLayerOpacity={setLayerOpacity} /> <ZoomControl /> {options.layers.includes('cadastres') && ( <div className="cadastres-selection-control mapboxgl-ctrl-group"> <button type="button" onClick={() => setCadastreEnabled((cadastreEnabled) => !cadastreEnabled) } title="Sélectionner les parcelles cadastrales" className={cadastreEnabled ? 'on' : ''} > <CursorClickIcon className="icon-size" /> </button> </div> )} </Mapbox> <PointInput /> </> ); } function PointInput() { const inputId = useId(); const [value, setValue] = useState(''); const [feature, setFeature] = useState(null); const getCurrentPosition = () => { navigator.geolocation && navigator.geolocation.getCurrentPosition(({ coords }) => { setValue( `${coords.latitude.toPrecision(6)}, ${coords.longitude.toPrecision( 6 )}` ); }); }; const addPoint = () => { if (feature) { fire(document, 'map:feature:create', feature); setValue(''); setFeature(null); } }; return ( <> <label className="areas-title mt-1" htmlFor={inputId} style={{ fontSize: '16px' }} > Ajouter un point sur la carte </label> <div className="flex align-center mt-1 mb-2"> {navigator.geolocation ? ( <button type="button" className="button mr-1" onClick={getCurrentPosition} title="Localiser votre position" > <VisuallyHidden>Localiser votre position</VisuallyHidden> <LocationMarkerIcon className="icon-size-big" /> </button> ) : null} <CoordinateInput id={inputId} className="m-0 mr-1" value={value} onChange={(value, { dd }) => { setValue(value); setFeature( dd.length ? { type: 'Feature', geometry: { type: 'Point', coordinates: dd.reverse() }, properties: {} } : null ); }} /> <button type="button" className="button" onClick={addPoint} disabled={!feature} title="Ajouter le point avec les coordonnées saisies sur la carte" > <VisuallyHidden> Ajouter le point avec les coordonnées saisies sur la carte </VisuallyHidden> <PlusIcon className="icon-size-big" /> </button> </div> </> ); } MapEditor.propTypes = { featureCollection: PropTypes.shape({ bbox: PropTypes.array, features: PropTypes.array }), url: PropTypes.string, preview: PropTypes.bool, options: PropTypes.shape({ layers: PropTypes.array }) }; export default MapEditor;