Skip to content

Commit

Permalink
Draw voie
Browse files Browse the repository at this point in the history
  • Loading branch information
tmerlier committed Sep 8, 2020
1 parent 8b1a73f commit 4ee47d4
Show file tree
Hide file tree
Showing 13 changed files with 328 additions and 61 deletions.
71 changes: 71 additions & 0 deletions components/bal/draw-editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, {useContext, useCallback, useMemo} from 'react'
import PropTypes from 'prop-types'
import {Pane, Button, Alert} from 'evergreen-ui'
import {isEqual} from 'lodash'

import DrawContext from '../../contexts/draw'

const DrawEditor = ({lineVoie}) => {
const {modeId, data, setData} = useContext(DrawContext)

const handleCancel = useCallback(() => {
setData(lineVoie)
}, [setData, lineVoie])

const isModified = useMemo(() => {
if (data && lineVoie) {
return !isEqual(data.geometry.coordinates, lineVoie.geometry.coordinates, isEqual)
}

return false
}, [data, lineVoie])

return (
<Pane>
{isModified && (
<Button
type='button'
marginY={8} marginRight={12}
iconBefore='edit'
onClick={handleCancel}
>
Annuler les modifications
</Button>
)}

{data && (
<Button
type='button'
intent='danger'
marginY={8} marginRight={12}
iconBefore='eraser'
onClick={() => setData(null)}
>
Effacer le tracé
</Button>
)}

<Alert
intent='none'
title='Utilisez la carte pour dessiner le tracer de la voie'
marginBottom={32}
>
{modeId === 'drawLineString' ?
'Cliquez sur la carte pour indiquer le début de la voie, puis ajouter de nouveaux points afin de tracer votre voie. Une fois terminé, cliquez sur le dernier point afin d’indiquer la fin de la voie.' :
'Modifier le tracé de la voie directement depuis la carte.'
}
</Alert>

</Pane>
)
}

DrawEditor.defaultProps = {
lineVoie: null
}

DrawEditor.propTypes = {
lineVoie: PropTypes.object
}

export default DrawEditor
56 changes: 50 additions & 6 deletions components/bal/voie-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,54 @@ import React, {useState, useMemo, useContext, useCallback, useEffect} from 'reac
import PropTypes from 'prop-types'
import {Pane, Button, Checkbox, Alert, TextInputField} from 'evergreen-ui'

import {checkIsToponyme} from '../../lib/voie'

import DrawContext from '../../contexts/draw'
import MarkerContext from '../../contexts/marker'

import {useInput, useCheckboxInput} from '../../hooks/input'
import useFocus from '../../hooks/focus'
import useKeyEvent from '../../hooks/key-event'

import PositionEditor from './position-editor'
import DrawEditor from './draw-editor'

function VoieEditor({initialValue, onSubmit, onCancel, isEnabledComplement}) {
const position = initialValue ? initialValue.positions[0] : null

const [isLoading, setIsLoading] = useState(false)
const [isToponyme, onIsToponymeChange] = useCheckboxInput(Boolean(position))
const [isToponyme, onIsToponymeChange] = useCheckboxInput(checkIsToponyme(initialValue))
const [isMetric, onIsMetricChange] = useCheckboxInput(initialValue ? initialValue.typeNumerotation === 'metric' : false)
const [nom, onNomChange] = useInput(initialValue ? initialValue.nom : '')
const [complement, onComplementChange] = useInput(initialValue ? initialValue.complement : '')
const [positionType, onPositionTypeChange] = useInput(position ? position.type : 'entrée')
const [error, setError] = useState()
const setRef = useFocus()

const {data, setModeId, setData} = useContext(DrawContext)
const {
enabled,
marker,
enableMarker,
disableMarker
} = useContext(MarkerContext)

const onUnmount = useCallback(() => {
disableMarker()
setData(null)
setModeId(null)
}, [disableMarker, setData, setModeId])

const onFormSubmit = useCallback(async e => {
e.preventDefault()

setIsLoading(true)

const body = {
nom,
complement: complement.length > 1 ? complement : null
typeNumerotation: isMetric ? 'metric' : 'numeric',
complement: complement.length > 1 ? complement : null,
lineVoie: data
}

if (marker) {
Expand All @@ -52,19 +66,19 @@ function VoieEditor({initialValue, onSubmit, onCancel, isEnabledComplement}) {

try {
await onSubmit(body)
disableMarker()
onUnmount()
} catch (error) {
setIsLoading(false)
setError(error.message)
}
}, [nom, marker, positionType, onSubmit, disableMarker, complement])
}, [nom, isMetric, complement, data, marker, positionType, onSubmit, onUnmount])

const onFormCancel = useCallback(e => {
e.preventDefault()

disableMarker()
onUnmount()
onCancel()
}, [disableMarker, onCancel])
}, [onCancel, onUnmount])

const submitLabel = useMemo(() => {
if (isLoading) {
Expand All @@ -89,6 +103,24 @@ function VoieEditor({initialValue, onSubmit, onCancel, isEnabledComplement}) {
}
}, [enabled, initialValue, disableMarker, enableMarker, isToponyme, position])

useEffect(() => {
if (isMetric) {
onIsToponymeChange({target: {checked: false}})
}
}, [isMetric, onIsToponymeChange])

useEffect(() => {
if (isToponyme) {
onIsMetricChange({target: {checked: false}})
}
}, [isToponyme, onIsMetricChange])

useEffect(() => {
return () => {
console.log('UNMOUNT')
}
}, [])

return (
<Pane is='form' onSubmit={onFormSubmit}>
<TextInputField
Expand Down Expand Up @@ -120,6 +152,12 @@ function VoieEditor({initialValue, onSubmit, onCancel, isEnabledComplement}) {
/>
)}

<Checkbox
checked={isMetric}
label='Cette voie utilise la numérotation métrique'
onChange={onIsMetricChange}
/>

{!initialValue && (
<Checkbox
checked={isToponyme}
Expand All @@ -128,6 +166,10 @@ function VoieEditor({initialValue, onSubmit, onCancel, isEnabledComplement}) {
/>
)}

{isMetric && (
<DrawEditor voieLine={initialValue ? initialValue.lineVoie : null} />
)}

{isToponyme && marker && (
<PositionEditor
initialValue={position}
Expand Down Expand Up @@ -171,6 +213,8 @@ VoieEditor.propTypes = {
initialValue: PropTypes.shape({
nom: PropTypes.string,
complement: PropTypes.string,
typeNumerotation: PropTypes.string,
lineVoie: PropTypes.object,
positions: PropTypes.array.isRequired
}),
onSubmit: PropTypes.func.isRequired,
Expand Down
69 changes: 69 additions & 0 deletions components/map/draw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React, {useCallback, useMemo, useContext} from 'react'
import PropTypes from 'prop-types'
import {Popup} from 'react-map-gl'
import {Editor, EditingMode, DrawLineStringMode} from 'react-map-gl-draw'
import {Text} from 'evergreen-ui'

import DrawContext from '../../contexts/draw'

const MODES = {
editing: EditingMode,
drawLineString: DrawLineStringMode
}

const Draw = ({hoverPos}) => {
const {modeId, data, hint, setHint, setData} = useContext(DrawContext)

const _onUpdate = useCallback(({data, editType}) => {
if (editType === 'addTentativePosition') {
setHint('Cliquez pour ajouter un point ou cliquez sur le dernier pour terminer la voie')
}

if (data) {
setData(data[0])
console.log('setData')
}
}, [setData, setHint])

const mode = useMemo(() => {
const Mode = MODES[modeId]
return Mode ? new Mode() : null
}, [modeId])

if (!mode) {
return null
}

return (
<>
<Editor
style={{width: '100%', height: '100%'}}
clickRadius={12}
mode={mode}
features={data ? [data] : null}
editHandleShape='circle'
onUpdate={_onUpdate}
/>

{hoverPos && hint && (
<Popup {...hoverPos} closeButton={false}>
<Text>{hint}</Text>
</Popup>
)}
</>
)
}

Draw.defaultProps = {
lineVoie: null,
hoverPos: null
}

Draw.propTypes = {
lineVoie: PropTypes.array,
hoverPos: PropTypes.object,
handleVoieLine: PropTypes.func.isRequired,
setModeId: PropTypes.func.isRequired
}

export default Draw
2 changes: 1 addition & 1 deletion components/map/editable-marker.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function EditableMarker({viewport, size, style}) {
onDrag={onDrag}
>
<Pane>
{editingItem && (
{editingItem && editingItem.positions && (
<Text
position='absolute'
top={-58}
Expand Down
16 changes: 14 additions & 2 deletions components/map/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Pane, SelectMenu, Icon, Button, Position} from 'evergreen-ui'

import BalDataContext from '../../contexts/bal-data'
import TokenContext from '../../contexts/token'
import DrawContext from '../../contexts/draw'
import MarkerContext from '../../contexts/marker'

import {addNumero, addVoie} from '../../lib/bal-api'
Expand All @@ -20,6 +21,7 @@ import EditableMarker from './editable-marker'
import Control from './control'
import NumeroMarker from './numero-marker'
import ToponymeMarker from './toponyme-marker'
import Draw from './draw'

import useBounds from './hooks/bounds'
import useSources from './hooks/sources'
Expand Down Expand Up @@ -94,7 +96,10 @@ function Map({interactive, style: defaultStyle, commune, voie}) {
const [mapStyle, setMapStyle] = useState(getBaseStyle(defaultStyle))
const [showPopover, setShowPopover] = useState(false)

const [hoverPos, setHoverPos] = useState(null)

const {baseLocale, numeros, reloadNumeros, toponymes, reloadVoies, editingId} = useContext(BalDataContext)
const {modeId} = useContext(DrawContext)
const {enableMarker, disableMarker} = useContext(MarkerContext)
const {token} = useContext(TokenContext)

Expand Down Expand Up @@ -147,14 +152,17 @@ function Map({interactive, style: defaultStyle, commune, voie}) {
setShowContextMenu(null)
}, [baseLocale, commune])

const onHover = event => {
const onHover = useCallback(event => {
const feature = event.features && event.features[0]

const {lng, lat} = map.unproject(event.point)
setHoverPos({longitude: lng, latitude: lat})

if (feature) {
const {idVoie} = feature.properties
setHovered(idVoie)
}
}
}, [map])

const onAddAddress = useCallback(async (body, idVoie) => {
if (idVoie) {
Expand Down Expand Up @@ -228,11 +236,13 @@ function Map({interactive, style: defaultStyle, commune, voie}) {
{...settings}
{...getInteractionProps(interactive)}
interactiveLayerIds={interactiveLayerIds}
getCursor={() => modeId === 'drawLineString' ? 'crosshair' : 'default'}
onClick={onClick}
onHover={onHover}
onMouseLeave={() => setHovered(null)}
onViewportChange={onViewportChange}
>

{interactive && (
<>
<NavControl onViewportChange={onViewportChange} />
Expand Down Expand Up @@ -316,6 +326,8 @@ function Map({interactive, style: defaultStyle, commune, voie}) {
viewport={viewport}
style={style || defaultStyle}
/>

<Draw hoverPos={hoverPos} />
</MapGl>
</Pane>

Expand Down
4 changes: 2 additions & 2 deletions contexts/bal-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ export const BalDataContextProvider = React.memo(({balId, codeCommune, idVoie, .
if (editingId) {
return numeros ?
numeros.find(numero => numero._id === editingId) :
toponymes.find(toponyme => toponyme._id === editingId)
voies.find(voie => voie._id === editingId)
}
}, [editingId, numeros, toponymes])
}, [editingId, numeros, voies])

useEffect(() => {
reloadGeojson()
Expand Down
Loading

0 comments on commit 4ee47d4

Please sign in to comment.