Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Tableau de bord] Ajout d'un bouton pour effacer la zone lors de l'édition #1883

Merged
merged 1 commit into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/src/domain/entities/layers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function addGeometryToMultiGeometryGeoJSON(

export function keepOnlyInitialGeometriesOfMultiGeometry(
multiGeometry: GeoJSONType.Geometry,
initialFeatureNumber: number
initialFeatureNumber?: number
): GeoJSONType.Geometry | undefined {
const nextGeometry = new GeoJSON({
featureProjection: OPENLAYERS_PROJECTION
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/domain/shared_slices/Draw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ const drawReducerSlice = createSlice({
state.initialGeometry = undefined
},

setGeometry(state, action: PayloadAction<GeoJSON.Geometry>) {
setGeometry(state, action: PayloadAction<GeoJSON.Geometry | undefined>) {
state.geometry = action.payload
state.isGeometryValid = isGeometryValid(action.payload)
},
/**
* Save the initial geometry value from form if user want to reinitialize the geometry
*/
setInitialGeometry(state, action: PayloadAction<GeoJSON.Geometry>) {
setInitialGeometry(state, action: PayloadAction<GeoJSON.Geometry | undefined>) {
state.initialGeometry = action.payload
},

Expand Down
22 changes: 13 additions & 9 deletions frontend/src/domain/use_cases/draw/eraseDrawedGeometries.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { keepOnlyInitialGeometriesOfMultiGeometry } from '../../entities/layers'
import { setGeometry } from '../../shared_slices/Draw'

export const eraseDrawedGeometries = initialFeatureNumber => (dispatch, getState) => {
const { geometry } = getState().draw
if (!geometry) {
return
}
import type { HomeAppThunk } from '@store/index'

export const eraseDrawedGeometries =
(initialFeatureNumber?: number): HomeAppThunk =>
(dispatch, getState) => {
const { geometry } = getState().draw
if (!geometry) {
return
}

const nextGeometry = keepOnlyInitialGeometriesOfMultiGeometry(geometry, initialFeatureNumber)
if (nextGeometry) {
dispatch(setGeometry(nextGeometry))
const nextGeometry = keepOnlyInitialGeometriesOfMultiGeometry(geometry, initialFeatureNumber)
if (nextGeometry) {
dispatch(setGeometry(nextGeometry))
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { dashboardActions } from '@features/Dashboard/slice'
import { useAppDispatch } from '@hooks/useAppDispatch'
import { useListenForDrawedGeometry } from '@hooks/useListenForDrawing'
import { Accent, Icon, IconButton, OPENLAYERS_PROJECTION, THEME, WSG84_PROJECTION } from '@mtes-mct/monitor-ui'
Expand All @@ -13,10 +14,11 @@ import type { GeoJSON } from 'domain/types/GeoJSON'
import type { Coordinate } from 'ol/coordinate'

type EditAreaProps = {
dashboardKey: string
geometry: GeoJSON.Geometry | undefined
onValidate: (geometry: GeoJSON.Geometry) => void
}
export function EditArea({ geometry, onValidate }: EditAreaProps) {
export function EditArea({ dashboardKey, geometry, onValidate }: EditAreaProps) {
const [geometryToSave, setGeometryToSave] = useState<GeoJSON.Geometry | undefined>(undefined)
const { geometry: geometryInProgress, interactionType } = useListenForDrawedGeometry(
InteractionListener.DASHBOARD_ZONE
Expand All @@ -30,18 +32,20 @@ export function EditArea({ geometry, onValidate }: EditAreaProps) {
}

const handleEditArea = useCallback(() => {
dispatch(drawCircle(undefined, InteractionListener.DASHBOARD_ZONE))
}, [dispatch])
dispatch(drawCircle(geometry, InteractionListener.DASHBOARD_ZONE))
}, [dispatch, geometry])

useEffect(() => {
if (interactionType) {
setGeometryToSave(geometryInProgress)
dispatch(dashboardActions.setDisplayGeometry({ key: dashboardKey, visible: false }))
}
}, [dispatch, geometryInProgress, interactionType])
}, [dashboardKey, dispatch, geometryInProgress, interactionType])

useEffect(() => {
if (geometryToSave && (geometryToSave as GeoJSON.MultiPolygon).coordinates.length > 0 && !interactionType) {
onValidate(geometryToSave)
dispatch(dashboardActions.setDisplayGeometry({ key: dashboardKey, visible: true }))
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [interactionType, geometryToSave])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const Toolbar = forwardRef<HTMLDivElement, ToolbarProps>(
return (
<Wrapper ref={ref}>
<EditArea
dashboardKey={key}
geometry={geometry}
onValidate={geometryToSave => {
dispatch(editDashboardArea(geometryToSave, key))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export function ActiveDashboardLayer({ map }: BaseMapChildrenProps) {
const displayDashboardLayer = useAppSelector(state => state.global.displayDashboardLayer)

const activeDashboardId = useAppSelector(state => state.dashboard.activeDashboardId)
const displayGeometry = useAppSelector(state =>
activeDashboardId ? state.dashboard.dashboards?.[activeDashboardId]?.displayGeometry : false
)

const dashboard = useAppSelector(state => getDashboardById(state.dashboard, activeDashboardId))
const { data: reportings } = useGetReportingsByIdsQuery(dashboard?.dashboard.reportingIds ?? [], {
Expand Down Expand Up @@ -168,7 +171,7 @@ export function ActiveDashboardLayer({ map }: BaseMapChildrenProps) {
}
}

if (dashboard?.dashboard.geom) {
if (dashboard?.dashboard.geom && displayGeometry) {
const dashboardAreaFeature = getFeature(dashboard.dashboard.geom)
if (!dashboardAreaFeature) {
return
Expand All @@ -192,7 +195,8 @@ export function ActiveDashboardLayer({ map }: BaseMapChildrenProps) {
vigilanceAreas?.entities,
reportings,
dashboard?.dashboard.geom,
drawBorder
drawBorder,
displayGeometry
])

useEffect(() => {
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/features/Dashboard/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const initialDashboard: DashboardType = {
vigilanceAreaIds: []
},
defaultName: '',
displayGeometry: true,
extractedArea: undefined,
isEditingTabName: false,
openPanel: undefined,
Expand All @@ -40,6 +41,7 @@ export type DashboardType = {
ampIdsToDisplay: number[]
dashboard: Dashboard.Dashboard
defaultName: string | undefined
displayGeometry: boolean
extractedArea?: Dashboard.ExtractedArea
isEditingTabName: boolean
openPanel: OpenPanel | undefined
Expand Down Expand Up @@ -284,6 +286,15 @@ export const dashboardSlice = createSlice({
state.dashboards[id].openPanel = action.payload
}
},
setDisplayGeometry(state, action: PayloadAction<{ key: string; visible: boolean }>) {
const id = action.payload.key

if (!id || !state.dashboards[id]) {
return
}

state.dashboards[id].displayGeometry = action.payload.visible
},
setGeometry(state, action: PayloadAction<GeoJSON.Geometry | undefined>) {
state.geometry = action.payload
state.isGeometryValid = action.payload ? isGeometryValid(action.payload) : true
Expand Down
17 changes: 13 additions & 4 deletions frontend/src/features/commonComponents/Modals/MapInteraction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type MapInteractionProps = {
customTools?: React.ReactNode
isValidatedButtonDisabled?: boolean
onCancel?: () => void
onDelete?: () => void
onReset: () => void
onValidate: () => void
resetButtonText?: string
Expand All @@ -17,6 +18,7 @@ export function MapInteraction({
customTools = undefined,
isValidatedButtonDisabled = false,
onCancel,
onDelete,
onReset,
onValidate,
resetButtonText = undefined,
Expand All @@ -36,6 +38,11 @@ export function MapInteraction({
<ButtonRow $withCustomTools={!!customTools}>
{customTools}
<ButtonGroup>
{!!onDelete && (
<DeleteButton accent={Accent.SECONDARY} Icon={Icon.Delete} onClick={onDelete}>
Tout effacer
</DeleteButton>
)}
<Button accent={Accent.SECONDARY} onClick={onReset}>
{resetButtonText ?? 'Réinitialiser'}
</Button>
Expand Down Expand Up @@ -78,10 +85,8 @@ const Title = styled.h1`
`

const ButtonGroup = styled.div`
display: inline-block;
& > :not(:last-child) {
margin-right: 16px;
}
display: flex;
gap: 16px;
`

const ValidateButton = styled(Button)`
Expand All @@ -101,3 +106,7 @@ const Body = styled.div`
padding: 24px;
background-color: ${p => p.theme.color.white};
`

const DeleteButton = styled(Button)`
color: ${p => p.theme.color.maximumRed};
`
9 changes: 8 additions & 1 deletion frontend/src/features/map/draw/DrawModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Coordinates, CoordinatesInput, IconButton, Icon, usePrevious } from '@mtes-mct/monitor-ui'
import { type Coordinates, CoordinatesInput, Icon, IconButton, usePrevious } from '@mtes-mct/monitor-ui'
import { getFeature } from '@utils/getFeature'
import Feature from 'ol/Feature'
import Point from 'ol/geom/Point'
Expand Down Expand Up @@ -53,6 +53,7 @@ export function DrawModal() {
const initialGeometry = useAppSelector(state => state.draw.initialGeometry)
const interactionType = useAppSelector(state => state.draw.interactionType)
const isGeometryValid = useAppSelector(state => state.draw.isGeometryValid)

const listener = useAppSelector(state => state.draw.listener)

const global = useAppSelector(state => state.global)
Expand Down Expand Up @@ -143,6 +144,11 @@ export function DrawModal() {
dispatch(setGeometry(initialGeometry))
}

const handleDelete = () => {
dispatch(eraseDrawedGeometries(initialFeatureNumberRef.current))
dispatch(setGeometry(undefined))
}

const handleValidate = () => {
dispatch(updateMapInteractionListeners(MapInteractionListenerEnum.NONE))
}
Expand Down Expand Up @@ -209,6 +215,7 @@ export function DrawModal() {
}
isValidatedButtonDisabled={!isGeometryValid}
onCancel={handleCancel}
onDelete={listener === InteractionListener.DASHBOARD_ZONE ? handleDelete : undefined}
onReset={handleReset}
onValidate={handleValidate}
title={`${listener && titlePlaceholder[listener]}`}
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/features/map/layers/DrawLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ function UnmemoizedDrawLayer({ map }: BaseMapChildrenProps) {
)

useEffect(() => {
vectorSourceRef.current.clear(true)
drawVectorSourceRef.current.clear(true)
if (isEmpty(feature) || !interactionType) {
return undefined
}

resetModifyInteractions(map)
vectorSourceRef.current.clear(true)
drawVectorSourceRef.current.clear(true)

vectorSourceRef.current.addFeature(feature)
const modify = new Modify({
source: vectorSourceRef.current
Expand Down
8 changes: 1 addition & 7 deletions frontend/src/hooks/useDrawVectorLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,7 @@ type VectorLayerWithName = VectorLayer & { name?: string }

export function useDrawVectorLayer(geometry: any, layerName: string) {
// Memoize the feature creation
const feature = useMemo(() => {
if (!geometry) {
return undefined
}

return getFeature(geometry)
}, [geometry])
const feature = useMemo(() => getFeature(geometry), [geometry])

// Create the vector sources and layer references
const vectorSourceRef = useRef(
Expand Down
11 changes: 7 additions & 4 deletions frontend/src/utils/geometryValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,18 @@ function isPolygonValid(polygon: Coordinate[][]) {
return true
}

function arePolygonsValid(polygons: Coordinate[][][]) {
function arePolygonsValid(polygons: Coordinate[][][] | undefined) {
return reduce(polygons, (result, polygon) => result && isPolygonValid(polygon), true)
}

export function isGeometryValid(geometry: GeoJSON.Geometry) {
if (geometry && geometry.type === OLGeometryType.MULTIPOLYGON) {
export function isGeometryValid(geometry: GeoJSON.Geometry | undefined) {
if (!geometry) {
return false
}
if (geometry.type === OLGeometryType.MULTIPOLYGON) {
return !!geometry.coordinates.length && arePolygonsValid(geometry.coordinates as Coordinate[][][])
}
if (geometry && geometry.type === OLGeometryType.POLYGON) {
if (geometry.type === OLGeometryType.POLYGON) {
return isPolygonValid(geometry.coordinates as Coordinate[][])
}

Expand Down
Loading