Skip to content

Commit

Permalink
[Dashboard] add selected regulatoryAreas accordion and fix Panel
Browse files Browse the repository at this point in the history
  • Loading branch information
claire2212 committed Sep 24, 2024
1 parent 8e8d060 commit fd48c76
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Accent, Icon, IconButton, Size } from '@mtes-mct/monitor-ui'
import { Accent, Icon, IconButton } from '@mtes-mct/monitor-ui'
import styled from 'styled-components'

type AccordionProps = {
Expand All @@ -22,7 +22,6 @@ export function Accordion({ children, headerButton, isExpanded, setExpandedAccor
accent={Accent.TERTIARY}
Icon={Icon.Chevron}
onClick={setExpandedAccordion}
size={Size.SMALL}
/>
</AccordionHeader>
<HeaderSeparator />
Expand All @@ -39,7 +38,7 @@ const StyledIconButton = styled(IconButton)<{ $isExpanded: boolean }>`
transform: ${({ $isExpanded }) => ($isExpanded ? 'rotate(180deg)' : 'rotate(0deg)')};
transition: transform 0.3s;
`
const AccordionHeader = styled.div`
const AccordionHeader = styled.header`
display: flex;
justify-content: space-between;
padding: 24px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Accent, Icon, IconButton, THEME } from '@mtes-mct/monitor-ui'
import { transformExtent } from 'ol/proj'
import Projection from 'ol/proj/Projection'
import { createRef } from 'react'
import styled from 'styled-components'

import { useGetRegulatoryLayersQuery } from '../../../../../api/regulatoryLayersAPI'
import { MonitorEnvLayers } from '../../../../../domain/entities/layers/constants'
Expand All @@ -16,10 +17,11 @@ import { useAppDispatch } from '../../../../../hooks/useAppDispatch'

type RegulatoryLayerProps = {
dashboardId: number
isSelected: boolean
layerId: number
}

export function Layer({ dashboardId, layerId }: RegulatoryLayerProps) {
export function Layer({ dashboardId, isSelected, layerId }: RegulatoryLayerProps) {
const dispatch = useAppDispatch()
const ref = createRef<HTMLSpanElement>()

Expand Down Expand Up @@ -54,16 +56,17 @@ export function Layer({ dashboardId, layerId }: RegulatoryLayerProps) {
}
}

const removeZone = e => {
e.stopPropagation()
dispatch(dashboardActions.removeItems({ itemIds: [layerId], type: Dashboard.Block.REGULATORY_AREAS }))
}

const toggleZoneMetadata = () => {
dispatch(dashboardActions.setDashboardPanel({ id: layerId, type: Dashboard.Block.REGULATORY_AREAS }))
}

return (
<LayerSelector.Layer
ref={ref}
// $metadataIsShown={metadataIsShown}
onClick={toggleZoneMetadata}
>
<StyledLayer ref={ref} onClick={toggleZoneMetadata}>
<LayerLegend
layerType={MonitorEnvLayers.REGULATORY_ENV}
legendKey={layer?.entity_name ?? 'aucun'}
Expand All @@ -74,15 +77,31 @@ export function Layer({ dashboardId, layerId }: RegulatoryLayerProps) {
</LayerSelector.Name>

<LayerSelector.IconGroup>
<IconButton
accent={Accent.TERTIARY}
aria-label="Sélectionner la zone"
color={isZoneSelected ? THEME.color.blueGray : THEME.color.slateGray}
data-cy="regulatory-zone-check"
Icon={isZoneSelected ? Icon.PinFilled : Icon.Pin}
onClick={handleSelectZone}
/>
{isSelected ? (
<IconButton
accent={Accent.TERTIARY}
aria-label="Supprimer la zone"
color={THEME.color.slateGray}
Icon={Icon.Close}
onClick={removeZone}
title="Supprimer la/ zone"
/>
) : (
<IconButton
accent={Accent.TERTIARY}
aria-label="Sélectionner la zone"
color={isZoneSelected ? THEME.color.blueGray : THEME.color.slateGray}
data-cy="regulatory-zone-check"
Icon={isZoneSelected ? Icon.PinFilled : Icon.Pin}
onClick={handleSelectZone}
/>
)}
</LayerSelector.IconGroup>
</LayerSelector.Layer>
</StyledLayer>
)
}

const StyledLayer = styled(LayerSelector.Layer)`
padding-left: 24px;
padding-right: 24px;
`
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ import { Accent, Icon, IconButton, THEME } from '@mtes-mct/monitor-ui'
import { getTitle } from 'domain/entities/layers/utils'
import { includes, intersection } from 'lodash'
import { useState } from 'react'
import styled from 'styled-components'

import { Layer } from './Layer'

type ResultListLayerGroupProps = {
dashboardId: number
groupName: string
isSelected?: boolean
layerIds: number[]
}
export function ListLayerGroup({ dashboardId, groupName, layerIds }: ResultListLayerGroupProps) {
export function ListLayerGroup({ dashboardId, groupName, isSelected = false, layerIds }: ResultListLayerGroupProps) {
const dispatch = useAppDispatch()
const [zonesAreOpen, setZonesAreOpen] = useState(false)

Expand All @@ -40,34 +42,55 @@ export function ListLayerGroup({ dashboardId, groupName, layerIds }: ResultListL
}
}

const removeAllZones = e => {
e.stopPropagation()
const payload = { itemIds: layerIds, type: Dashboard.Block.REGULATORY_AREAS }
dispatch(dashboardActions.removeItems(payload))
}

const clickOnGroupZones = () => {
setZonesAreOpen(!zonesAreOpen)
}

return (
<>
<LayerSelector.GroupWrapper $isOpen={forceZonesAreOpen || zonesAreOpen} onClick={clickOnGroupZones}>
<StyledGroupWrapper $isOpen={forceZonesAreOpen || zonesAreOpen} onClick={clickOnGroupZones}>
<LayerSelector.GroupName data-cy="result-group" title={groupName}>
{getTitle(groupName) ?? ''}
</LayerSelector.GroupName>
<LayerSelector.IconGroup>
<LayerSelector.ZonesNumber>{`${layerIds.length}/${totalNumberOfZones}`}</LayerSelector.ZonesNumber>

<IconButton
accent={Accent.TERTIARY}
aria-label="Sélectionner la/les zone(s)"
color={allTopicZonesAreChecked ? THEME.color.blueGray : THEME.color.slateGray}
Icon={allTopicZonesAreChecked ? Icon.PinFilled : Icon.Pin}
onClick={handleCheckAllZones}
title="Sélectionner la/les zone(s)"
/>
{isSelected ? (
<IconButton
accent={Accent.TERTIARY}
aria-label="Supprimer la/les zone(s)"
color={THEME.color.slateGray}
Icon={Icon.Close}
onClick={removeAllZones}
title="Supprimer la/les zone(s)"
/>
) : (
<IconButton
accent={Accent.TERTIARY}
aria-label="Sélectionner la/les zone(s)"
color={allTopicZonesAreChecked ? THEME.color.blueGray : THEME.color.slateGray}
Icon={allTopicZonesAreChecked ? Icon.PinFilled : Icon.Pin}
onClick={handleCheckAllZones}
title="Sélectionner la/les zone(s)"
/>
)}
</LayerSelector.IconGroup>
</LayerSelector.GroupWrapper>
</StyledGroupWrapper>
<LayerSelector.SubGroup isOpen={forceZonesAreOpen || zonesAreOpen} length={layerIds?.length}>
{layerIds?.map(layerId => (
<Layer key={layerId} dashboardId={dashboardId} layerId={layerId} />
<Layer key={layerId} dashboardId={dashboardId} isSelected={isSelected} layerId={layerId} />
))}
</LayerSelector.SubGroup>
</>
)
}

const StyledGroupWrapper = styled(LayerSelector.GroupWrapper)`
padding-left: 24px;
padding-right: 24px;
`
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import { Accent, Icon, IconButton } from '@mtes-mct/monitor-ui'
import { skipToken } from '@reduxjs/toolkit/query'
import { MonitorEnvLayers } from 'domain/entities/layers/constants'
import { getTitle } from 'domain/entities/layers/utils'
import { useEffect } from 'react'
import { FingerprintSpinner } from 'react-epic-spinners'
import styled from 'styled-components'

const FOUR_HOURS = 4 * 60 * 60 * 1000

export function RegulatoryPanel({ dashboardId }: { dashboardId: number }) {
export function RegulatoryPanel({ $marginLeft, dashboardId }: { $marginLeft: number; dashboardId: number }) {
const dispatch = useAppDispatch()
const openPanel = useAppSelector(state => state.dashboard.dashboards?.[dashboardId]?.openPanel)

Expand All @@ -26,8 +27,18 @@ export function RegulatoryPanel({ dashboardId }: { dashboardId: number }) {
dispatch(dashboardActions.setDashboardPanel())
}

useEffect(
() => () => {
dispatch(dashboardActions.setDashboardPanel())
},
[dispatch]
)
if (!openPanel) {
return null
}

return (
<Wrapper $isOpen={!!openPanel}>
<Wrapper $isOpen={!!openPanel} $marginLeft={$marginLeft}>
{regulatoryMetadata ? (
<>
<Header data-cy="regulatory-metadata-header">
Expand Down Expand Up @@ -63,16 +74,16 @@ export function RegulatoryPanel({ dashboardId }: { dashboardId: number }) {
)
}

const Wrapper = styled.div<{ $isOpen: boolean }>`
const Wrapper = styled.div<{ $isOpen: boolean; $marginLeft: number }>`
background-color: ${p => p.theme.color.white};
box-shadow: 0px 3px 5px #70778540;
display: block;
margin-left: 37px;
opacity: ${p => (p.$isOpen ? 1 : 0)};
position: absolute;
transform: translateX(100%);
transition: all 0.5s;
width: 400px;
z-index: 1;
left: ${p =>
`calc(
${p.$marginLeft}px + 40px + 64px + 20px
)`}; // 40px is the padding, 64px is the width of the lsidebar, 20px is the margin
`

const RegulatoryZoneName = styled.span`
Expand All @@ -86,7 +97,7 @@ const RegulatoryZoneName = styled.span`
margin-right: 5px;
`

const Header = styled.div`
const Header = styled.header`
background-color: ${p => p.theme.color.gainsboro};
color: ${p => p.theme.color.gunMetal};
text-align: left;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,50 @@
import { useGetRegulatoryLayersQuery } from '@api/regulatoryLayersAPI'
import { Dashboard } from '@features/Dashboard/types'
import { LayerSelector } from '@features/layersSelector/utils/LayerSelector.style'
import { useAppSelector } from '@hooks/useAppSelector'
import { pluralize } from '@mtes-mct/monitor-ui'
import { groupBy } from 'lodash'
import { useRef, useState } from 'react'
import styled from 'styled-components'

import { ListLayerGroup } from './ListLayerGroup'
import { RegulatoryPanel } from './Panel'
import { Accordion } from '../Accordion'
import { SmallAccordion } from '../SmallAccordion'

type RegulatoriesAreasProps = {
dashboardId: number
isExpanded: boolean
setExpandedAccordion: () => void
}
export function RegulatoryAreas({ dashboardId, isExpanded, setExpandedAccordion }: RegulatoriesAreasProps) {
const ref = useRef<HTMLDivElement>(null)
const width = ref.current?.clientWidth

const selectedLayerIds = useAppSelector(
state => state.dashboard.dashboards?.[dashboardId]?.[Dashboard.Block.REGULATORY_AREAS]
)

const [isExpandedSmallAccordion, setExpandedSmallAccordion] = useState(false)
const { data: regulatoryLayers } = useGetRegulatoryLayersQuery()

const regulatoryAreasByLayerName = groupBy(
Object.values(regulatoryLayers?.ids ?? {}),
r => regulatoryLayers?.entities[r]?.layer_name
(r: number) => regulatoryLayers?.entities[r]?.layer_name
)

const selectedRegulatoryAreaIds = Object.values(regulatoryLayers?.ids ?? {}).filter(id =>
selectedLayerIds?.includes(id)
)
const selectedRegulatoryAreasByLayerName = groupBy(
selectedRegulatoryAreaIds,
(r: number) => regulatoryLayers?.entities[r]?.layer_name
)

return (
<div>
<RegulatoryPanel dashboardId={dashboardId} />
<div ref={ref}>
<RegulatoryPanel $marginLeft={width ?? 0} dashboardId={dashboardId} />

<Accordion isExpanded={isExpanded} setExpandedAccordion={setExpandedAccordion} title="Zones règlementaires">
<StyledLayerList
$baseLayersLength={Object.values(regulatoryAreasByLayerName).length}
Expand All @@ -39,6 +61,25 @@ export function RegulatoryAreas({ dashboardId, isExpanded, setExpandedAccordion
))}
</StyledLayerList>
</Accordion>
<SmallAccordion
isExpanded={isExpandedSmallAccordion}
isReadOnly={selectedLayerIds?.length === 0}
setExpandedAccordion={() => setExpandedSmallAccordion(!isExpandedSmallAccordion)}
title={`${selectedLayerIds?.length ?? 0} ${pluralize('zone', selectedLayerIds?.length ?? 0)} ${pluralize(
'sélectionée',
selectedLayerIds?.length ?? 0
)}`}
>
{Object.entries(selectedRegulatoryAreasByLayerName).map(([layerGroupName, layerIdsInGroup]) => (
<ListLayerGroup
key={layerGroupName}
dashboardId={dashboardId}
groupName={layerGroupName}
isSelected
layerIds={layerIdsInGroup}
/>
))}
</SmallAccordion>
</div>
)
}
Expand Down
Loading

0 comments on commit fd48c76

Please sign in to comment.