Skip to content

Commit

Permalink
[Unités carto] Régler l'affichage de l'Overlay (#2799)
Browse files Browse the repository at this point in the history
## Linked issues

- Resolve #2740
- Resolve #2793

----

- [ ] Tests E2E (Cypress)
  • Loading branch information
ivangabriele authored Jan 16, 2024
2 parents 52923ce + 623ffa2 commit 4e6169d
Show file tree
Hide file tree
Showing 22 changed files with 316 additions and 252 deletions.
8 changes: 4 additions & 4 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"dependencies": {
"@dnd-kit/core": "6.0.8",
"@dnd-kit/modifiers": "6.0.1",
"@mtes-mct/monitor-ui": "10.15.1",
"@mtes-mct/monitor-ui": "10.17.1",
"@reduxjs/toolkit": "1.9.6",
"@sentry/browser": "7.55.2",
"@sentry/react": "7.52.1",
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/components/OverlayCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ export type DialogProps = HtmlHTMLAttributes<HTMLDivElement> & {
export function OverlayCard({ children, isCloseButtonHidden = false, onClose, title, ...props }: DialogProps) {
return (
<StyledMapMenuDialogContainer {...props}>
<MapMenuDialog.Header>
<StyledMapMenuDialogHeader>
<StyledMapMenuDialogTitle title={title}>{title}</StyledMapMenuDialogTitle>
<MapMenuDialog.CloseButton
Icon={Icon.Close}
onClick={onClose}
style={{ visibility: isCloseButtonHidden ? 'hidden' : 'visible' }}
/>
</MapMenuDialog.Header>
</StyledMapMenuDialogHeader>
{children}
</StyledMapMenuDialogContainer>
)
Expand All @@ -29,6 +29,10 @@ const StyledMapMenuDialogContainer = styled(MapMenuDialog.Container)`
margin: 0;
`

const StyledMapMenuDialogHeader = styled(MapMenuDialog.Header)`
cursor: grabbing;
`

const StyledMapMenuDialogTitle = styled(MapMenuDialog.Title)`
display: block;
flex-grow: 1;
Expand Down
18 changes: 1 addition & 17 deletions frontend/src/domain/use_cases/map/clickOnMapFeature.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import GeoJSON from 'ol/format/GeoJSON'

import { showRegulatoryZoneMetadata } from '../../../features/Regulation/useCases/showRegulatoryZoneMetadata'
import {
FEATURE_MARGINS,
STATION_OVERLAY_DIALOG_WIDTH_AND_HEIGHT
} from '../../../features/Station/components/SelectedStationOverlay/constants'
import { stationActions } from '../../../features/Station/slice'
import { FeatureWithCodeAndEntityId } from '../../../libs/FeatureWithCodeAndEntityId'
import { getDialogOverlayPositionFromFeature } from '../../../utils/getDialogOverlayPositionFromFeature'
import { missionActions } from '../../actions'
import { isControl } from '../../entities/controls'
import { LayerProperties } from '../../entities/layers/constants'
Expand Down Expand Up @@ -70,18 +65,7 @@ export const clickOnMapFeature = (mapClick: MapClick) => (dispatch, getState) =>
}

if (mapClick.feature instanceof FeatureWithCodeAndEntityId && mapClick.feature.code === MonitorFishLayer.STATION) {
const overlayPosition = getDialogOverlayPositionFromFeature(
mapClick.feature,
STATION_OVERLAY_DIALOG_WIDTH_AND_HEIGHT,
FEATURE_MARGINS
)

dispatch(
stationActions.selectStation({
overlayPosition,
stationId: mapClick.feature.entityId
})
)
dispatch(stationActions.selectStationId(mapClick.feature.entityId))

return
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/features/MainWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function MainWindow() {

<PreviewFilteredVessels />

<Wrapper>
<Wrapper id="mainWindowWrapper">
<Map />
<LayersSidebar />
{isVesselSearchDisplayed && <VesselSidebarHeader />}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { useMemo, useRef } from 'react'
import { useForceUpdate, type Coordinates } from '@mtes-mct/monitor-ui'
import { useEffect, useMemo, useRef } from 'react'
import styled from 'styled-components'

import { FEATURE_MARGINS } from './constants'
import { MonitorFishLayer } from '../../../../domain/entities/layers/types'
import { useMainAppSelector } from '../../../../hooks/useMainAppSelector'
import { getDialogWindowPositionFromFeature } from '../../../../utils/getDialogWindowPositionFromFeature'
import { useGetStationsQuery } from '../../stationApi'
import { StationCard } from '../StationCard'
import { StationCard } from './StationCard'
import { MonitorFishLayer } from '../../../domain/entities/layers/types'
import { useMainAppSelector } from '../../../hooks/useMainAppSelector'
import { getDialogWindowPositionFromFeature } from '../../../utils/getDialogWindowPositionFromFeature'
import { FEATURE_MARGINS } from '../constants'
import { useGetStationsQuery } from '../stationApi'

import type { FeatureWithCodeAndEntityId } from '../../../../libs/FeatureWithCodeAndEntityId'
import type { Coordinates } from '@mtes-mct/monitor-ui'
import type { FeatureWithCodeAndEntityId } from '../../../libs/FeatureWithCodeAndEntityId'

type HoveredStationOverlayProps = {
hoveredFeature: FeatureWithCodeAndEntityId | undefined
Expand All @@ -24,6 +24,7 @@ export function HoveredStationOverlay({ hoveredFeature }: HoveredStationOverlayP
: undefined

const { data: stations } = useGetStationsQuery()
const { forceUpdate } = useForceUpdate()

const hoveredStation = useMemo(
() => (hoveredStationId ? stations?.find(station => station.id === hoveredStationId) : undefined),
Expand All @@ -37,6 +38,12 @@ export function HoveredStationOverlay({ hoveredFeature }: HoveredStationOverlayP
[hoverDialogElementRef.current, hoveredStationId]
)

useEffect(() => {
if (hoveredStationId !== undefined) {
forceUpdate()
}
}, [forceUpdate, hoveredStationId])

return (
<Wrapper $isVisible={!!hoverDialogElementRef.current} $topLeftPosition={wrapperWindowPosition}>
{hoveredStation && <StationCard ref={hoverDialogElementRef} station={hoveredStation} />}
Expand All @@ -49,10 +56,9 @@ const Wrapper = styled.div<{
$topLeftPosition: Coordinates
}>`
border-radius: 2px;
cursor: grabbing;
left: ${p => p.$topLeftPosition[1]}px;
position: absolute;
top: ${p => p.$topLeftPosition[0]}px;
z-index: 5001;
visibility: ${p => (p.$isVisible ? 'visible' : 'hidden')};
z-index: 5001;
`

This file was deleted.

140 changes: 140 additions & 0 deletions frontend/src/features/Station/components/SelectedStationOverlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { useForceUpdate } from '@mtes-mct/monitor-ui'
import { Overlay } from 'ol'
import { useCallback, useEffect, useMemo, useRef } from 'react'
import styled from 'styled-components'

import { StationCard } from './StationCard'
import { getStationPointFeature } from './StationLayer/utils'
import { useMainAppSelector } from '../../../hooks/useMainAppSelector'
import { useMoveOverlayWhenDragging } from '../../../hooks/useMoveOverlayWhenDragging'
import { getDialogOverlayOffsetFromFeature } from '../../../utils/getDialogOverlayOffsetFromFeature'
import { monitorfishMap } from '../../map/monitorfishMap'
import { FEATURE_MARGINS } from '../constants'
import { useGetStationsQuery } from '../stationApi'

import type { FeatureWithCodeAndEntityId } from '../../../libs/FeatureWithCodeAndEntityId'
import type { Geometry } from 'ol/geom'

export function SelectedStationOverlay() {
const wrapperElementRef = useRef<HTMLDivElement | null>(null)
const selectionDialogElementRef = useRef<HTMLDivElement | null>(null)
const overlayRef = useRef<Overlay | undefined>(undefined)
const currentOffsetRef = useRef([0, 0])

const isStationLayerDisplayed = useMainAppSelector(state => state.displayedComponent.isStationLayerDisplayed)
const selectedStationId = useMainAppSelector(state => state.station.selectedStationId)
const { data: stations } = useGetStationsQuery()
const { forceUpdate } = useForceUpdate()

const selectedStation = useMemo(
() => (selectedStationId ? stations?.find(station => station.id === selectedStationId) : undefined),
[stations, selectedStationId]
)
const selectedStationFeature = useMemo(
() => (selectedStation ? getStationPointFeature(selectedStation) : undefined),
[selectedStation]
)

const removeOverlay = useCallback(() => {
if (!overlayRef.current) {
return
}

monitorfishMap.removeOverlay(overlayRef.current)

overlayRef.current = undefined
}, [])

const updateOverlay = useCallback(
(feature: FeatureWithCodeAndEntityId<Geometry>, wrapperElement: HTMLDivElement) => {
const nextOverlay = new Overlay({
className: 'ol-overlay-container overlay-active',
element: wrapperElement
})
nextOverlay.setProperties({ entityId: feature.entityId })
nextOverlay.setPosition(feature.getGeometry()?.getExtent())
nextOverlay.setOffset(currentOffsetRef.current)

removeOverlay()

overlayRef.current = nextOverlay

monitorfishMap.addOverlay(nextOverlay)
},
[removeOverlay]
)

useEffect(() => {
if (
!wrapperElementRef.current ||
!selectionDialogElementRef.current ||
!selectedStationFeature ||
overlayRef.current?.getProperties().entityId === selectedStationFeature.entityId
) {
if (!selectedStationFeature) {
removeOverlay()
}

return
}

updateOverlay(selectedStationFeature, wrapperElementRef.current)
}, [removeOverlay, selectedStationFeature, updateOverlay])

useMoveOverlayWhenDragging(
overlayRef.current,
currentOffsetRef,
() => {},
true,
() => {}
)

useEffect(() => {
if (selectedStationId !== undefined) {
forceUpdate()
}

if (
overlayRef.current &&
selectedStationFeature &&
selectionDialogElementRef.current?.offsetWidth &&
selectionDialogElementRef.current?.offsetWidth > 0
) {
currentOffsetRef.current = getDialogOverlayOffsetFromFeature(
selectedStationFeature,
selectionDialogElementRef.current,
FEATURE_MARGINS
)

overlayRef.current.setOffset(currentOffsetRef.current)
}
}, [
forceUpdate,
isStationLayerDisplayed,
selectedStationFeature,
selectedStationId,
selectionDialogElementRef.current?.offsetWidth
])

useEffect(() => () => removeOverlay(), [removeOverlay])

return (
<WrapperToBeKeptForDOMManagement $isVisible={!!selectionDialogElementRef.current} id="selected-station-overlay">
<div ref={wrapperElementRef}>
{isStationLayerDisplayed && selectedStation && (
<StationCard ref={selectionDialogElementRef} isSelected station={selectedStation} />
)}
</div>
</WrapperToBeKeptForDOMManagement>
)
}

const WrapperToBeKeptForDOMManagement = styled.div<{
$isVisible: boolean
}>`
left: 0;
position: absolute;
top: 0;
visibility: ${p => (p.$isVisible ? 'visible' : 'hidden')};
z-index: 5000;
`

This file was deleted.

This file was deleted.

Loading

0 comments on commit 4e6169d

Please sign in to comment.