From f679938a507b4e52ac1a13795b3397a690460eb2 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Tue, 23 Apr 2024 22:13:16 +0200 Subject: [PATCH 01/16] Create LeftMenu & migrate global slice into MainWindow feature --- .../e2e/missions/missions_map_button.spec.ts | 2 +- .../e2e/vessel_sidebar/logbook.spec.ts | 1 - frontend/src/api/APIWorker.tsx | 2 +- frontend/src/api/BackofficeMode.tsx | 2 +- frontend/src/domain/entities/vessel/vessel.ts | 4 +- frontend/src/domain/shared_slices/Vessel.ts | 11 +- .../use_cases/alert/addSilencedAlert.ts | 2 +- .../use_cases/alert/getOperationalAlerts.ts | 2 +- .../use_cases/alert/getSilencedAlerts.ts | 2 +- .../alert/reactivateSilencedAlert.ts | 2 +- .../domain/use_cases/alert/silenceAlert.ts | 2 +- .../domain/use_cases/alert/validateAlert.ts | 2 +- .../getAllBeaconMalfunctions.js | 2 +- .../getVesselBeaconMalfunctions.ts | 2 +- .../openBeaconMalfunction.js | 2 +- .../openBeaconMalfunctionInKanban.ts | 2 +- .../saveBeaconMalfunctionCommentFromKanban.js | 4 +- .../beaconMalfunction/sendNotification.ts | 2 +- .../updateBeaconMalfunctionFromKanban.js | 2 +- .../use_cases/error/displayOrLogError.ts | 2 +- .../domain/use_cases/faoAreas/getFAOAreas.js | 2 +- .../use_cases/gearCode/getAllGearCodes.js | 2 +- .../use_cases/infraction/getInfractions.ts | 2 +- .../domain/use_cases/map/clickOnMapFeature.ts | 2 +- .../use_cases/measurement/saveMeasurement.js | 4 +- .../use_cases/mission/getVesselControls.ts | 2 +- .../domain/use_cases/species/getAllSpecies.js | 2 +- .../domain/use_cases/vessel/searchVessels.ts | 2 +- .../src/domain/use_cases/vessel/showVessel.ts | 4 +- .../use_cases/vessel/showVesselTrack.ts | 2 +- .../domain/use_cases/vessel/unselectVessel.ts | 2 +- .../updateSelectedVesselTrackRequest.ts | 2 +- .../features/Account/components/Account.tsx | 6 +- .../layers/AdministrativeLayers.tsx | 2 +- .../useCases/getAdministrativeZoneGeometry.js | 2 +- .../useCases/getAdministrativeZones.ts | 4 +- .../useCases/getZonesAndSubZonesPromises.js | 2 +- .../edit_regulation/EditRegulation.tsx | 2 +- .../components/ControlUnitDialog/index.tsx | 2 +- .../components/ControlUnitListMapButton.tsx | 4 +- .../useCases/addFleetSegmentYear.ts | 2 +- .../useCases/createFleetSegment.ts | 2 +- .../useCases/deleteFleetSegment.ts | 2 +- .../useCases/getFleetSegmentsYearEntries.ts | 2 +- .../useCases/updateFleetSegment.ts | 2 +- .../components/HealthcheckHeadband.tsx | 6 +- .../InterestPointMapButton/index.tsx | 4 +- .../layers/InterestPointLayer.jsx | 239 +++++++++--------- .../LayersSidebar/components/index.tsx | 8 +- .../Logbook/useCases/getVesselLogbook.ts | 2 +- .../MainWindow/components/LeftMenu.tsx | 156 ++++++++++++ .../components/MapButtons/AlertsMapButton.tsx | 66 ----- .../BeaconMalfunctionsMapButton.tsx | 2 +- .../MapButtons/FavoriteVessels/index.tsx | 6 +- .../components/MapButtons/MapButton.tsx | 7 +- .../components/MapButtons/Missions/index.tsx | 149 ----------- .../MapButtons/VesselFilters/Filters.tsx | 2 +- .../MapButtons/VesselFilters/index.tsx | 6 +- .../VesselLabels/EditVesselLabels.tsx | 2 +- .../MapButtons/VesselLabels/index.tsx | 6 +- .../VesselVisibility/EditVesselVisibility.tsx | 2 +- .../MapButtons/VesselVisibility/index.tsx | 6 +- .../components/MapButtons/index.tsx | 5 - .../MapButtons/shared/MapToolButton.tsx | 4 +- .../shared/RightMenuOnHoverArea.tsx | 4 +- frontend/src/features/MainWindow/index.tsx | 29 ++- .../MainWindow/slice.ts} | 65 +++-- .../CustomCircleRange.tsx | 6 +- .../components/MeasurementMapButton/index.tsx | 6 +- .../Mission/components/MissionMenuDialog.tsx | 129 ++++++++++ .../components/RegulationSearch/constants.ts | 2 +- .../getAllRegulatoryLayersByRegTerritory.ts | 4 +- .../getGeometryWithoutRegulationReference.ts | 4 +- .../useCases/searchRegulatoryLayers.ts | 6 +- .../useCases/showRegulationToEdit.js | 5 +- .../Regulation/useCases/showRegulatoryZone.js | 2 +- .../useCases/showRegulatoryZoneMetadata.ts | 4 +- .../Regulation/useCases/updateRegulation.js | 3 +- .../useCases/updateTopicForAllZones.js | 2 +- .../Reporting/useCases/addReporting.ts | 10 + .../Reporting/useCases/deleteReporting.ts | 10 + .../useCases/getAllCurrentReportings.ts | 2 +- .../Reporting/useCases/getVesselReportings.ts | 2 +- .../SilenceAlertMenu.tsx | 2 +- .../BeaconMalfunctionDetailsFollowUp.tsx | 4 +- .../BeaconMalfunctionBoard/index.tsx | 2 +- .../Vessel/components/VesselLoader.tsx | 8 +- .../Vessel/useCases/applyFilterToVessels.ts | 2 +- .../useCases/showVesselsLastPosition.ts | 2 +- frontend/src/features/VesselList/index.tsx | 6 +- .../VesselSearch/VesselSearchResult.tsx | 2 +- frontend/src/features/VesselSearch/index.tsx | 3 +- frontend/src/features/VesselSidebar/Body.tsx | 2 +- .../VesselSidebarHeader/VesselName.tsx | 10 + .../VesselSidebarHeader/index.tsx | 8 +- .../actions/TrackRequest/index.tsx | 2 +- .../actions/animate_to_track/index.tsx | 2 +- .../hide_non_selected_vessels/index.tsx | 2 +- .../actions/show_fishing_activities/index.tsx | 2 +- frontend/src/features/VesselSidebar/index.tsx | 2 +- .../ErrorToastNotification.tsx | 2 +- .../features/commonStyles/MapComponent.tsx | 7 - frontend/src/features/map/BaseMap.tsx | 25 +- .../VesselAlertAndBeaconMalfunctionLayer.jsx | 72 +++--- .../map/layers/Vessel/VesselAlertLayer.jsx | 76 +++--- .../Vessel/VesselBeaconMalfunctionLayer.jsx | 72 +++--- .../Vessel/VesselEstimatedPositionLayer.jsx | 80 +++--- .../Vessel/VesselInfractionSuspicionLayer.jsx | 76 +++--- .../map/layers/Vessel/VesselsLabelsLayer.tsx | 2 +- .../map/layers/Vessel/VesselsLayer/index.tsx | 2 +- .../PreviewFilteredVessels.jsx | 11 +- .../useClickOutsideWhenOpenedWithinRef.jsx | 34 --- .../useClickOutsideWhenOpenedWithinRef.tsx | 48 ++++ frontend/src/store/reducers.ts | 4 +- frontend/src/ui/NoRsuiteOverrideWrapper.tsx | 4 + 115 files changed, 924 insertions(+), 739 deletions(-) create mode 100644 frontend/src/features/MainWindow/components/LeftMenu.tsx delete mode 100644 frontend/src/features/MainWindow/components/MapButtons/AlertsMapButton.tsx delete mode 100644 frontend/src/features/MainWindow/components/MapButtons/Missions/index.tsx rename frontend/src/{domain/shared_slices/Global.ts => features/MainWindow/slice.ts} (78%) create mode 100644 frontend/src/features/Mission/components/MissionMenuDialog.tsx delete mode 100644 frontend/src/hooks/useClickOutsideWhenOpenedWithinRef.jsx create mode 100644 frontend/src/hooks/useClickOutsideWhenOpenedWithinRef.tsx diff --git a/frontend/cypress/e2e/missions/missions_map_button.spec.ts b/frontend/cypress/e2e/missions/missions_map_button.spec.ts index 2677d67c65..2a7b49513c 100644 --- a/frontend/cypress/e2e/missions/missions_map_button.spec.ts +++ b/frontend/cypress/e2e/missions/missions_map_button.spec.ts @@ -6,7 +6,7 @@ context('Missions Map Button', () => { it('Mission layer Should be showed and hidden', () => { // Given cy.get('.MISSION_PIN_POINT').should('exist') - cy.get('*[data-cy^="missions-menu-box"]').should('not.be.visible') + cy.get('*[data-cy^="missions-menu-box"]').should('not.exist') cy.get('*[data-cy="mission-label-text"]').should('have.length', 1) // When diff --git a/frontend/cypress/e2e/vessel_sidebar/logbook.spec.ts b/frontend/cypress/e2e/vessel_sidebar/logbook.spec.ts index edce7c176d..285140f2f3 100644 --- a/frontend/cypress/e2e/vessel_sidebar/logbook.spec.ts +++ b/frontend/cypress/e2e/vessel_sidebar/logbook.spec.ts @@ -198,7 +198,6 @@ context('Vessel sidebar logbook tab', () => { // When cy.get('*[data-cy^="vessel-menu-fishing"]').click({ timeout: 10000 }) cy.get('*[data-cy^="vessel-fishing-see-all"]').click({ timeout: 10000 }) - cy.scrollTo(0, 380) cy.get('*[data-cy^="show-fishing-activity"]').eq(8).parent().contains('Retour au port') cy.get('*[data-cy^="show-fishing-activity"]').eq(8).scrollIntoView().click({ timeout: 20000 }) diff --git a/frontend/src/api/APIWorker.tsx b/frontend/src/api/APIWorker.tsx index 90ba45ac7c..6365d386d0 100644 --- a/frontend/src/api/APIWorker.tsx +++ b/frontend/src/api/APIWorker.tsx @@ -6,7 +6,6 @@ import { useEffect, useRef, useState } from 'react' import { useIsSuperUser } from '../auth/hooks/useIsSuperUser' import { SideWindowStatus } from '../domain/entities/sideWindow/constants' import { VesselSidebarTab } from '../domain/entities/vessel/vessel' -import { setIsUpdatingVessels } from '../domain/shared_slices/Global' import { getOperationalAlerts } from '../domain/use_cases/alert/getOperationalAlerts' import { getSilencedAlerts } from '../domain/use_cases/alert/getSilencedAlerts' import getAllBeaconMalfunctions from '../domain/use_cases/beaconMalfunction/getAllBeaconMalfunctions' @@ -17,6 +16,7 @@ import { getInfractions } from '../domain/use_cases/infraction/getInfractions' import { getVesselControls } from '../domain/use_cases/mission/getVesselControls' import getAllSpecies from '../domain/use_cases/species/getAllSpecies' import { updateVesselTracks } from '../domain/use_cases/vessel/updateVesselTracks' +import { setIsUpdatingVessels } from '../features/MainWindow/slice' import { getAllCurrentReportings } from '../features/Reporting/useCases/getAllCurrentReportings' import { useMainAppDispatch } from '../hooks/useMainAppDispatch' import { useMainAppSelector } from '../hooks/useMainAppSelector' diff --git a/frontend/src/api/BackofficeMode.tsx b/frontend/src/api/BackofficeMode.tsx index f7494f194b..e119965d18 100644 --- a/frontend/src/api/BackofficeMode.tsx +++ b/frontend/src/api/BackofficeMode.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react' -import { setIsBackoffice } from '../domain/shared_slices/Global' +import { setIsBackoffice } from '../features/MainWindow/slice' import { useMainAppDispatch } from '../hooks/useMainAppDispatch' export type BackofficeModeProps = { diff --git a/frontend/src/domain/entities/vessel/vessel.ts b/frontend/src/domain/entities/vessel/vessel.ts index 026ede19ef..4498e7060a 100644 --- a/frontend/src/domain/entities/vessel/vessel.ts +++ b/frontend/src/domain/entities/vessel/vessel.ts @@ -26,7 +26,7 @@ export const VESSEL_SELECTOR_STYLE = 200 export class Vessel { static vesselIsMovingSpeed = 0.1 - static getVesselFeatureId(vessel) { + static getVesselFeatureId(vessel: VesselIdentity) { return `${MonitorFishLayer.VESSELS}:${getVesselCompositeIdentifier(vessel)}` } @@ -157,7 +157,7 @@ export const getOnlyVesselIdentityProperties = ( vesselName: vessel.vesselName ?? null }) -export const getVesselCompositeIdentifier: (vessel) => VesselCompositeIdentifier = vessel => +export const getVesselCompositeIdentifier: (vessel: VesselIdentity) => VesselCompositeIdentifier = vessel => `${vessel.internalReferenceNumber ?? 'UNKNOWN'}/${vessel.ircs ?? 'UNKNOWN'}/${ vessel.externalReferenceNumber ?? 'UNKNOWN' }` diff --git a/frontend/src/domain/shared_slices/Vessel.ts b/frontend/src/domain/shared_slices/Vessel.ts index 059ba48803..a95c7781ec 100644 --- a/frontend/src/domain/shared_slices/Vessel.ts +++ b/frontend/src/domain/shared_slices/Vessel.ts @@ -195,7 +195,13 @@ const vesselSlice = createSlice({ state.highlightedVesselTrackPosition = action.payload }, - loadingVessel(state, action) { + loadingVessel( + state, + action: PayloadAction<{ + calledFromCron: boolean + vesselIdentity: VesselIdentity + }> + ) { state.selectedVesselIdentity = action.payload.vesselIdentity state.vesselSidebarIsOpen = true if (!action.payload.calledFromCron) { @@ -303,7 +309,8 @@ const vesselSlice = createSlice({ }) if ( - state.selectedVessel && + !!state.selectedVessel && + !!state.selectedVesselIdentity && Vessel.getVesselFeatureId(state.selectedVesselIdentity) === action.payload.vesselFeatureId ) { const vesselReportingWithoutFirstFoundReportingType = state.selectedVessel.reportings?.reduce( diff --git a/frontend/src/domain/use_cases/alert/addSilencedAlert.ts b/frontend/src/domain/use_cases/alert/addSilencedAlert.ts index 9305d4db99..e7536cb560 100644 --- a/frontend/src/domain/use_cases/alert/addSilencedAlert.ts +++ b/frontend/src/domain/use_cases/alert/addSilencedAlert.ts @@ -1,6 +1,6 @@ import { alertApi } from '../../../api/alert' +import { setError } from '../../../features/MainWindow/slice' import { setSilencedAlerts } from '../../../features/SideWindow/Alert/slice' -import { setError } from '../../shared_slices/Global' import type { MainAppThunk } from '../../../store' import type { SilencedAlertData } from '../../entities/alerts/types' diff --git a/frontend/src/domain/use_cases/alert/getOperationalAlerts.ts b/frontend/src/domain/use_cases/alert/getOperationalAlerts.ts index 762440ce8a..6faca42709 100644 --- a/frontend/src/domain/use_cases/alert/getOperationalAlerts.ts +++ b/frontend/src/domain/use_cases/alert/getOperationalAlerts.ts @@ -1,6 +1,6 @@ import { getOperationalAlertsFromAPI } from '../../../api/alert' +import { setError } from '../../../features/MainWindow/slice' import { setPendingAlerts } from '../../../features/SideWindow/Alert/slice' -import { setError } from '../../shared_slices/Global' import type { MainAppThunk } from '../../../store' diff --git a/frontend/src/domain/use_cases/alert/getSilencedAlerts.ts b/frontend/src/domain/use_cases/alert/getSilencedAlerts.ts index b14c4c5175..515e970729 100644 --- a/frontend/src/domain/use_cases/alert/getSilencedAlerts.ts +++ b/frontend/src/domain/use_cases/alert/getSilencedAlerts.ts @@ -1,6 +1,6 @@ import { getSilencedAlertsFromAPI } from '../../../api/alert' +import { setError } from '../../../features/MainWindow/slice' import { setSilencedAlerts } from '../../../features/SideWindow/Alert/slice' -import { setError } from '../../shared_slices/Global' export const getSilencedAlerts = () => dispatch => { getSilencedAlertsFromAPI() diff --git a/frontend/src/domain/use_cases/alert/reactivateSilencedAlert.ts b/frontend/src/domain/use_cases/alert/reactivateSilencedAlert.ts index ea2596bf90..6944916e2c 100644 --- a/frontend/src/domain/use_cases/alert/reactivateSilencedAlert.ts +++ b/frontend/src/domain/use_cases/alert/reactivateSilencedAlert.ts @@ -1,8 +1,8 @@ import { deleteSilencedAlertFromAPI } from '../../../api/alert' +import { setError } from '../../../features/MainWindow/slice' import { setSilencedAlerts } from '../../../features/SideWindow/Alert/slice' import { deleteListItems } from '../../../utils/deleteListItems' import { updateListItemsProp } from '../../../utils/updateListItemsProp' -import { setError } from '../../shared_slices/Global' import type { MainAppThunk } from '../../../store' import type { LEGACY_SilencedAlert } from '../../entities/alerts/types' diff --git a/frontend/src/domain/use_cases/alert/silenceAlert.ts b/frontend/src/domain/use_cases/alert/silenceAlert.ts index 38fc38ebbe..1786779589 100644 --- a/frontend/src/domain/use_cases/alert/silenceAlert.ts +++ b/frontend/src/domain/use_cases/alert/silenceAlert.ts @@ -1,4 +1,5 @@ import { silenceAlertFromAPI } from '../../../api/alert' +import { setError } from '../../../features/MainWindow/slice' import { addToPendingAlertsBeingSilenced, removeFromSilencedAlertsQueue, @@ -7,7 +8,6 @@ import { } from '../../../features/SideWindow/Alert/slice' import { deleteListItems } from '../../../utils/deleteListItems' import { Vessel } from '../../entities/vessel/vessel' -import { setError } from '../../shared_slices/Global' import { removeVesselAlertAndUpdateReporting } from '../../shared_slices/Vessel' import type { MainAppThunk } from '../../../store' diff --git a/frontend/src/domain/use_cases/alert/validateAlert.ts b/frontend/src/domain/use_cases/alert/validateAlert.ts index 033e39bd4b..8d42e2dc59 100644 --- a/frontend/src/domain/use_cases/alert/validateAlert.ts +++ b/frontend/src/domain/use_cases/alert/validateAlert.ts @@ -1,11 +1,11 @@ import { getVesselReportings } from '@features/Reporting/useCases/getVesselReportings' import { validateAlertFromAPI } from '../../../api/alert' +import { setError } from '../../../features/MainWindow/slice' import { setPendingAlerts } from '../../../features/SideWindow/Alert/slice' import { deleteListItems } from '../../../utils/deleteListItems' import { updateListItemsProp } from '../../../utils/updateListItemsProp' import { Vessel } from '../../entities/vessel/vessel' -import { setError } from '../../shared_slices/Global' import { removeVesselAlertAndUpdateReporting } from '../../shared_slices/Vessel' import type { MainAppThunk } from '../../../store' diff --git a/frontend/src/domain/use_cases/beaconMalfunction/getAllBeaconMalfunctions.js b/frontend/src/domain/use_cases/beaconMalfunction/getAllBeaconMalfunctions.js index fa5786319d..c21234b6fe 100644 --- a/frontend/src/domain/use_cases/beaconMalfunction/getAllBeaconMalfunctions.js +++ b/frontend/src/domain/use_cases/beaconMalfunction/getAllBeaconMalfunctions.js @@ -1,6 +1,6 @@ import { getAllBeaconMalfunctionsFromAPI } from '../../../api/beaconMalfunction' +import { setError } from '../../../features/MainWindow/slice' import { setBeaconMalfunctions } from '../../shared_slices/BeaconMalfunction' -import { setError } from '../../shared_slices/Global' const getAllBeaconMalfunctions = () => dispatch => { getAllBeaconMalfunctionsFromAPI() diff --git a/frontend/src/domain/use_cases/beaconMalfunction/getVesselBeaconMalfunctions.ts b/frontend/src/domain/use_cases/beaconMalfunction/getVesselBeaconMalfunctions.ts index 0570f80790..fd18e89a15 100644 --- a/frontend/src/domain/use_cases/beaconMalfunction/getVesselBeaconMalfunctions.ts +++ b/frontend/src/domain/use_cases/beaconMalfunction/getVesselBeaconMalfunctions.ts @@ -2,6 +2,7 @@ import { DisplayedErrorKey } from '@libs/DisplayedError/constants' import openBeaconMalfunction from './openBeaconMalfunction' import { getVesselBeaconsMalfunctionsFromAPI } from '../../../api/beaconMalfunction' +import { removeError } from '../../../features/MainWindow/slice' import { getOnlyVesselIdentityProperties } from '../../entities/vessel/vessel' import { loadVesselBeaconMalfunctions, @@ -9,7 +10,6 @@ import { setVesselBeaconMalfunctionsResumeAndHistory } from '../../shared_slices/BeaconMalfunction' import { displayedErrorActions } from '../../shared_slices/DisplayedError' -import { removeError } from '../../shared_slices/Global' import { displayOrLogError } from '../error/displayOrLogError' export const getVesselBeaconMalfunctions = (isFromUserAction: boolean) => async (dispatch, getState) => { diff --git a/frontend/src/domain/use_cases/beaconMalfunction/openBeaconMalfunction.js b/frontend/src/domain/use_cases/beaconMalfunction/openBeaconMalfunction.js index 67ceee6c4a..7306989eba 100644 --- a/frontend/src/domain/use_cases/beaconMalfunction/openBeaconMalfunction.js +++ b/frontend/src/domain/use_cases/beaconMalfunction/openBeaconMalfunction.js @@ -1,6 +1,6 @@ import { getBeaconMalfunctionFromAPI } from '../../../api/beaconMalfunction' +import { setError } from '../../../features/MainWindow/slice' import { setOpenedBeaconMalfunction } from '../../shared_slices/BeaconMalfunction' -import { setError } from '../../shared_slices/Global' /** * Open a single beacon malfunction diff --git a/frontend/src/domain/use_cases/beaconMalfunction/openBeaconMalfunctionInKanban.ts b/frontend/src/domain/use_cases/beaconMalfunction/openBeaconMalfunctionInKanban.ts index 634b9eedac..5592a76476 100644 --- a/frontend/src/domain/use_cases/beaconMalfunction/openBeaconMalfunctionInKanban.ts +++ b/frontend/src/domain/use_cases/beaconMalfunction/openBeaconMalfunctionInKanban.ts @@ -1,6 +1,6 @@ import { getBeaconMalfunctionFromAPI } from '../../../api/beaconMalfunction' +import { setError } from '../../../features/MainWindow/slice' import { setOpenedBeaconMalfunctionsInKanban } from '../../shared_slices/BeaconMalfunction' -import { setError } from '../../shared_slices/Global' /** * Open a single beacon malfunction diff --git a/frontend/src/domain/use_cases/beaconMalfunction/saveBeaconMalfunctionCommentFromKanban.js b/frontend/src/domain/use_cases/beaconMalfunction/saveBeaconMalfunctionCommentFromKanban.js index 4c1197d4da..5767b59331 100644 --- a/frontend/src/domain/use_cases/beaconMalfunction/saveBeaconMalfunctionCommentFromKanban.js +++ b/frontend/src/domain/use_cases/beaconMalfunction/saveBeaconMalfunctionCommentFromKanban.js @@ -1,10 +1,10 @@ import { saveBeaconMalfunctionCommentFromAPI } from '../../../api/beaconMalfunction' +import { setError } from '../../../features/MainWindow/slice' import { setOpenedBeaconMalfunction, setOpenedBeaconMalfunctionsInKanban, updateVesselBeaconMalfunctionsResumeAndHistory } from '../../shared_slices/BeaconMalfunction' -import { setError } from '../../shared_slices/Global' /** * Save a new comment to a beacon malfunction @@ -13,7 +13,7 @@ import { setError } from '../../shared_slices/Global' * @param {string} comment */ const saveBeaconMalfunctionCommentFromKanban = (beaconMalfunctionId, comment) => (dispatch, getState) => { - const { userType } = getState().global + const { userType } = getState().mainWindow const newCommentInput = { comment, userType diff --git a/frontend/src/domain/use_cases/beaconMalfunction/sendNotification.ts b/frontend/src/domain/use_cases/beaconMalfunction/sendNotification.ts index b521989d87..03d335a3b5 100644 --- a/frontend/src/domain/use_cases/beaconMalfunction/sendNotification.ts +++ b/frontend/src/domain/use_cases/beaconMalfunction/sendNotification.ts @@ -1,6 +1,6 @@ import { sendNotificationFromAPI } from '../../../api/beaconMalfunction' +import { setError } from '../../../features/MainWindow/slice' import { NOTIFICATION_TYPE } from '../../entities/beaconMalfunction/constants' -import { setError } from '../../shared_slices/Global' /** * Send a notification message diff --git a/frontend/src/domain/use_cases/beaconMalfunction/updateBeaconMalfunctionFromKanban.js b/frontend/src/domain/use_cases/beaconMalfunction/updateBeaconMalfunctionFromKanban.js index 09b31deb8a..5d071e2632 100644 --- a/frontend/src/domain/use_cases/beaconMalfunction/updateBeaconMalfunctionFromKanban.js +++ b/frontend/src/domain/use_cases/beaconMalfunction/updateBeaconMalfunctionFromKanban.js @@ -1,4 +1,5 @@ import { updateBeaconMalfunctionFromAPI } from '../../../api/beaconMalfunction' +import { setError } from '../../../features/MainWindow/slice' import { setBeaconMalfunctions, updateLocalBeaconMalfunction, @@ -6,7 +7,6 @@ import { setOpenedBeaconMalfunction, updateVesselBeaconMalfunctionsResumeAndHistory } from '../../shared_slices/BeaconMalfunction' -import { setError } from '../../shared_slices/Global' /** * Update a beacon malfunction diff --git a/frontend/src/domain/use_cases/error/displayOrLogError.ts b/frontend/src/domain/use_cases/error/displayOrLogError.ts index 940ab25744..071b7abdde 100644 --- a/frontend/src/domain/use_cases/error/displayOrLogError.ts +++ b/frontend/src/domain/use_cases/error/displayOrLogError.ts @@ -1,6 +1,6 @@ +import { setError } from '../../../features/MainWindow/slice' import { DisplayedError } from '../../../libs/DisplayedError' import { INITIAL_STATE, type DisplayedErrorState, displayedErrorActions } from '../../shared_slices/DisplayedError' -import { setError } from '../../shared_slices/Global' import type { MainAppUseCase } from '@store' diff --git a/frontend/src/domain/use_cases/faoAreas/getFAOAreas.js b/frontend/src/domain/use_cases/faoAreas/getFAOAreas.js index a92a454210..d6688b52d4 100644 --- a/frontend/src/domain/use_cases/faoAreas/getFAOAreas.js +++ b/frontend/src/domain/use_cases/faoAreas/getFAOAreas.js @@ -1,5 +1,5 @@ import { getFAOAreasFromAPI } from '../../../api/faoAreas' -import { setError } from '../../shared_slices/Global' +import { setError } from '../../../features/MainWindow/slice' const getFAOAreas = () => dispatch => getFAOAreasFromAPI().catch(error => { diff --git a/frontend/src/domain/use_cases/gearCode/getAllGearCodes.js b/frontend/src/domain/use_cases/gearCode/getAllGearCodes.js index 810040535a..833f20a405 100644 --- a/frontend/src/domain/use_cases/gearCode/getAllGearCodes.js +++ b/frontend/src/domain/use_cases/gearCode/getAllGearCodes.js @@ -1,9 +1,9 @@ import { batch } from 'react-redux' import { getAllGearsFromAPI } from '../../../api/gearCode' +import { setError } from '../../../features/MainWindow/slice' import { REGULATED_GEARS_KEYS } from '../../entities/backoffice' import { setCategoriesToGears, setGears, setGroupsToCategories, setGearsByCode } from '../../shared_slices/Gear' -import { setError } from '../../shared_slices/Global' /** * * Get gear group name, see SQL init of table fishing_gear_groups: diff --git a/frontend/src/domain/use_cases/infraction/getInfractions.ts b/frontend/src/domain/use_cases/infraction/getInfractions.ts index 6a5574ccc2..fe6e9c3141 100644 --- a/frontend/src/domain/use_cases/infraction/getInfractions.ts +++ b/frontend/src/domain/use_cases/infraction/getInfractions.ts @@ -1,5 +1,5 @@ import { getInfractionsFromAPI } from '../../../api/infraction' -import { setError } from '../../shared_slices/Global' +import { setError } from '../../../features/MainWindow/slice' import { setInfractions } from '../../shared_slices/Infraction' export const getInfractions = () => dispatch => { diff --git a/frontend/src/domain/use_cases/map/clickOnMapFeature.ts b/frontend/src/domain/use_cases/map/clickOnMapFeature.ts index 31f757f828..2173c4a114 100644 --- a/frontend/src/domain/use_cases/map/clickOnMapFeature.ts +++ b/frontend/src/domain/use_cases/map/clickOnMapFeature.ts @@ -68,7 +68,7 @@ export const clickOnMapFeature = return } - if (getState().global.previewFilteredVesselsMode) { + if (getState().mainWindow.previewFilteredVesselsMode) { return } diff --git a/frontend/src/domain/use_cases/measurement/saveMeasurement.js b/frontend/src/domain/use_cases/measurement/saveMeasurement.js index 74236fdf05..bd28308eb1 100644 --- a/frontend/src/domain/use_cases/measurement/saveMeasurement.js +++ b/frontend/src/domain/use_cases/measurement/saveMeasurement.js @@ -1,11 +1,11 @@ +import { addMeasurementDrawed, resetCircleMeasurementInDrawing } from '@features/Measurement/slice' import GeoJSON from 'ol/format/GeoJSON' import Circle from 'ol/geom/Circle' import { fromCircle } from 'ol/geom/Polygon' import { batch } from 'react-redux' +import { setRightMapBoxOpened } from '../../../features/MainWindow/slice' import { OPENLAYERS_PROJECTION } from '../../entities/map/constants' -import { setRightMapBoxOpened } from '../../shared_slices/Global' -import { addMeasurementDrawed, resetCircleMeasurementInDrawing } from '@features/Measurement/slice' const saveMeasurement = (feature, measurement) => dispatch => { feature.setId(feature.ol_uid) diff --git a/frontend/src/domain/use_cases/mission/getVesselControls.ts b/frontend/src/domain/use_cases/mission/getVesselControls.ts index fdea1aad76..3f43cd58d3 100644 --- a/frontend/src/domain/use_cases/mission/getVesselControls.ts +++ b/frontend/src/domain/use_cases/mission/getVesselControls.ts @@ -2,6 +2,7 @@ import { DisplayedErrorKey } from '@libs/DisplayedError/constants' import { getVesselControlsFromAPI } from '../../../api/missionAction' import NoControlsFoundError from '../../../errors/NoControlsFoundError' +import { removeError, setError } from '../../../features/MainWindow/slice' import { loadControls, resetLoadControls, @@ -10,7 +11,6 @@ import { unsetControlSummary } from '../../shared_slices/Control' import { displayedErrorActions } from '../../shared_slices/DisplayedError' -import { removeError, setError } from '../../shared_slices/Global' import { displayOrLogError } from '../error/displayOrLogError' export const getVesselControls = (isFromUserAction: boolean) => async (dispatch, getState) => { diff --git a/frontend/src/domain/use_cases/species/getAllSpecies.js b/frontend/src/domain/use_cases/species/getAllSpecies.js index bbffaaa89e..acdd5dd999 100644 --- a/frontend/src/domain/use_cases/species/getAllSpecies.js +++ b/frontend/src/domain/use_cases/species/getAllSpecies.js @@ -1,5 +1,5 @@ import { getAllSpeciesFromAPI } from '../../../api/species' -import { setError } from '../../shared_slices/Global' +import { setError } from '../../../features/MainWindow/slice' import { setSpeciesAndSpeciesGroups } from '../../shared_slices/Species' const getAllSpecies = () => async (dispatch, getState) => { diff --git a/frontend/src/domain/use_cases/vessel/searchVessels.ts b/frontend/src/domain/use_cases/vessel/searchVessels.ts index 837bfd5ddc..5c54e37636 100644 --- a/frontend/src/domain/use_cases/vessel/searchVessels.ts +++ b/frontend/src/domain/use_cases/vessel/searchVessels.ts @@ -1,5 +1,5 @@ import { searchVesselsFromAPI } from '../../../api/vessel' -import { setError } from '../../shared_slices/Global' +import { setError } from '../../../features/MainWindow/slice' export const searchVessels = searched => dispatch => searchVesselsFromAPI(searched).catch(error => { diff --git a/frontend/src/domain/use_cases/vessel/showVessel.ts b/frontend/src/domain/use_cases/vessel/showVessel.ts index 89f54f0ccc..3bede6f45e 100644 --- a/frontend/src/domain/use_cases/vessel/showVessel.ts +++ b/frontend/src/domain/use_cases/vessel/showVessel.ts @@ -3,11 +3,11 @@ import { captureMessage } from '@sentry/react' import { getVesselFromAPI } from '../../../api/vessel' import { logbookActions } from '../../../features/Logbook/slice' +import { addSearchedVessel, removeError, setError } from '../../../features/MainWindow/slice' import { Vessel } from '../../entities/vessel/vessel' import { getCustomOrDefaultTrackRequest, throwCustomErrorFromAPIFeedback } from '../../entities/vesselTrackDepth' import { displayedComponentActions } from '../../shared_slices/DisplayedComponent' import { displayedErrorActions } from '../../shared_slices/DisplayedError' -import { addSearchedVessel, removeError, setError } from '../../shared_slices/Global' import { doNotAnimate } from '../../shared_slices/Map' import { loadingVessel, resetLoadingVessel, setSelectedVessel } from '../../shared_slices/Vessel' import { displayOrLogError } from '../error/displayOrLogError' @@ -96,7 +96,7 @@ export const showVessel = } } -function dispatchLoadingVessel(dispatch, isFromUserAction: boolean, vesselIdentity) { +function dispatchLoadingVessel(dispatch, isFromUserAction: boolean, vesselIdentity: VesselIdentity) { dispatch(doNotAnimate(!isFromUserAction)) dispatch(removeError()) dispatch( diff --git a/frontend/src/domain/use_cases/vessel/showVesselTrack.ts b/frontend/src/domain/use_cases/vessel/showVesselTrack.ts index ad9a289c58..8f53e07b56 100644 --- a/frontend/src/domain/use_cases/vessel/showVesselTrack.ts +++ b/frontend/src/domain/use_cases/vessel/showVesselTrack.ts @@ -1,10 +1,10 @@ import { transform } from 'ol/proj' import { getVesselPositionsFromAPI } from '../../../api/vessel' +import { removeError, setError } from '../../../features/MainWindow/slice' import { OPENLAYERS_PROJECTION, WSG84_PROJECTION } from '../../entities/map/constants' import { getVesselCompositeIdentifier } from '../../entities/vessel/vessel' import { getCustomOrDefaultTrackRequest, throwCustomErrorFromAPIFeedback } from '../../entities/vesselTrackDepth' -import { removeError, setError } from '../../shared_slices/Global' import { doNotAnimate } from '../../shared_slices/Map' import { addVesselTrackShowed, resetLoadingVessel } from '../../shared_slices/Vessel' diff --git a/frontend/src/domain/use_cases/vessel/unselectVessel.ts b/frontend/src/domain/use_cases/vessel/unselectVessel.ts index df651528e2..0a173605b6 100644 --- a/frontend/src/domain/use_cases/vessel/unselectVessel.ts +++ b/frontend/src/domain/use_cases/vessel/unselectVessel.ts @@ -1,7 +1,7 @@ import { logbookActions } from '../../../features/Logbook/slice' +import { expandRightMenu } from '../../../features/MainWindow/slice' import { resetCurrentAndArchivedReportingsOfSelectedVessel } from '../../../features/Reporting/slice' import { resetVesselBeaconMalfunctionsResumeAndHistory } from '../../shared_slices/BeaconMalfunction' -import { expandRightMenu } from '../../shared_slices/Global' import { closeVesselSidebar, resetSelectedVessel } from '../../shared_slices/Vessel' export const unselectVessel = () => dispatch => { diff --git a/frontend/src/domain/use_cases/vessel/updateSelectedVesselTrackRequest.ts b/frontend/src/domain/use_cases/vessel/updateSelectedVesselTrackRequest.ts index 45400e1150..2fba421f82 100644 --- a/frontend/src/domain/use_cases/vessel/updateSelectedVesselTrackRequest.ts +++ b/frontend/src/domain/use_cases/vessel/updateSelectedVesselTrackRequest.ts @@ -1,7 +1,7 @@ import { getVesselPositionsFromAPI } from '../../../api/vessel' import { logbookActions } from '../../../features/Logbook/slice' +import { removeError, setError } from '../../../features/MainWindow/slice' import { throwCustomErrorFromAPIFeedback } from '../../entities/vesselTrackDepth' -import { removeError, setError } from '../../shared_slices/Global' import { animateToExtent, doNotAnimate } from '../../shared_slices/Map' import { resetLoadingVessel, diff --git a/frontend/src/features/Account/components/Account.tsx b/frontend/src/features/Account/components/Account.tsx index 4b825870bb..1875db15b0 100644 --- a/frontend/src/features/Account/components/Account.tsx +++ b/frontend/src/features/Account/components/Account.tsx @@ -8,15 +8,15 @@ import styled from 'styled-components' import { UserAccountContext } from '../../../context/UserAccountContext' import { MapBox } from '../../../domain/entities/map/constants' -import { setRightMapBoxOpened } from '../../../domain/shared_slices/Global' +import { setRightMapBoxOpened } from '../../MainWindow/slice' const MARGIN_TOP = 428 export function Account() { const dispatch = useMainAppDispatch() const userAccount = useContext(UserAccountContext) - const rightMapBoxOpened = useMainAppSelector(state => state.global.rightMapBoxOpened) - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const rightMapBoxOpened = useMainAppSelector(state => state.mainWindow.rightMapBoxOpened) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const openOrClose = () => { dispatch(setRightMapBoxOpened(rightMapBoxOpened === MapBox.ACCOUNT ? undefined : MapBox.ACCOUNT)) diff --git a/frontend/src/features/AdministrativeZone/layers/AdministrativeLayers.tsx b/frontend/src/features/AdministrativeZone/layers/AdministrativeLayers.tsx index 96bfaed913..0b3541f45e 100644 --- a/frontend/src/features/AdministrativeZone/layers/AdministrativeLayers.tsx +++ b/frontend/src/features/AdministrativeZone/layers/AdministrativeLayers.tsx @@ -13,7 +13,7 @@ import { getVectorOLLayer } from '../useCases/showAdministrativeZone' function UnmemoizedAdministrativeLayers() { const showedLayers = useMainAppSelector(state => state.layer.showedLayers) - const isBackoffice = useMainAppSelector(state => state.global.isBackoffice) + const isBackoffice = useMainAppSelector(state => state.mainWindow.isBackoffice) useEffect(() => { if (!showedLayers) { diff --git a/frontend/src/features/AdministrativeZone/useCases/getAdministrativeZoneGeometry.js b/frontend/src/features/AdministrativeZone/useCases/getAdministrativeZoneGeometry.js index 0cddd4e254..ca74ed1228 100644 --- a/frontend/src/features/AdministrativeZone/useCases/getAdministrativeZoneGeometry.js +++ b/frontend/src/features/AdministrativeZone/useCases/getAdministrativeZoneGeometry.js @@ -11,7 +11,7 @@ const getAdministrativeZoneGeometry = dispatchZoneSelected(foundCache.value) } - getAdministrativeZoneFromAPI(administrativeZoneCode, null, subZoneCode, getState().global.isBackoffice) + getAdministrativeZoneFromAPI(administrativeZoneCode, null, subZoneCode, getState().mainWindow.isBackoffice) .then(administrativeZoneFeature => { if (administrativeZoneFeature.numberReturned === 1) { dispatchZoneSelected(administrativeZoneFeature) diff --git a/frontend/src/features/AdministrativeZone/useCases/getAdministrativeZones.ts b/frontend/src/features/AdministrativeZone/useCases/getAdministrativeZones.ts index 7cfa0ad4d4..557ec7417f 100644 --- a/frontend/src/features/AdministrativeZone/useCases/getAdministrativeZones.ts +++ b/frontend/src/features/AdministrativeZone/useCases/getAdministrativeZones.ts @@ -36,14 +36,14 @@ export const getAdministrativeZones = .filter(zone => zone.type === LayerType.ADMINISTRATIVE) .filter(zone => zone.hasFetchableZones) .map(zone => - getAdministrativeSubZonesFromAPI(zone.code, getState().global.isBackoffice).then( + getAdministrativeSubZonesFromAPI(zone.code, getState().mainWindow.isBackoffice).then( (fetchedZones: GeoJSON.FeatureCollection) => { const nextZones: ShowableLayer[] = fetchedZones.features.map(feature => ({ code: feature.id!.toString(), group: zone.group, hasFetchableZones: zone.hasFetchableZones!, name: - (zone.zoneNamePropertyKey && feature.properties?.[zone.zoneNamePropertyKey]?.toString()) || 'Aucun nom', + (zone.zoneNamePropertyKey && feature.properties?.[zone.zoneNamePropertyKey]?.toString()) ?? 'Aucun nom', type: LayerType.ADMINISTRATIVE })) diff --git a/frontend/src/features/AdministrativeZone/useCases/getZonesAndSubZonesPromises.js b/frontend/src/features/AdministrativeZone/useCases/getZonesAndSubZonesPromises.js index 94df1e0f1c..28fc53db63 100644 --- a/frontend/src/features/AdministrativeZone/useCases/getZonesAndSubZonesPromises.js +++ b/frontend/src/features/AdministrativeZone/useCases/getZonesAndSubZonesPromises.js @@ -8,7 +8,7 @@ export const getZonesAndSubZonesPromises = () => (dispatch, getState) => .filter(layer => layer.isIntersectable) .map(zone => { if (zone.hasSearchableZones) { - return getAdministrativeSubZonesFromAPI(zone.code, getState().global.isBackoffice) + return getAdministrativeSubZonesFromAPI(zone.code, getState().mainWindow.isBackoffice) .then(subZonesFeatures => subZonesFeatures.features.map(subZone => ({ code: subZone.id, diff --git a/frontend/src/features/BackOffice/edit_regulation/EditRegulation.tsx b/frontend/src/features/BackOffice/edit_regulation/EditRegulation.tsx index 724204a1df..b52d7758e3 100644 --- a/frontend/src/features/BackOffice/edit_regulation/EditRegulation.tsx +++ b/frontend/src/features/BackOffice/edit_regulation/EditRegulation.tsx @@ -19,7 +19,6 @@ import ConfirmRegulationModal from './ConfirmRegulationModal' import SpeciesRegulation from './species_regulation/SpeciesRegulation' import { COLORS } from '../../../constants/constants' import { LayerProperties } from '../../../domain/entities/layers/constants' -import { setError } from '../../../domain/shared_slices/Global' import getAllSpecies from '../../../domain/use_cases/species/getAllSpecies' import { useBackofficeAppDispatch } from '../../../hooks/useBackofficeAppDispatch' import { useBackofficeAppSelector } from '../../../hooks/useBackofficeAppSelector' @@ -28,6 +27,7 @@ import { Footer, FooterButton, OtherRemark, Section, Title } from '../../commonS import { CancelButton, ValidateButton } from '../../commonStyles/Buttons.style' import { CustomInput, Label } from '../../commonStyles/Input.style' import ChevronIconSVG from '../../icons/Chevron_simple_gris.svg?react' +import { setError } from '../../MainWindow/slice' import { BaseMap } from '../../map/BaseMap' import { RegulatoryPreviewLayer } from '../../Regulation/layers/RegulatoryPreviewLayer' import { diff --git a/frontend/src/features/ControlUnit/components/ControlUnitDialog/index.tsx b/frontend/src/features/ControlUnit/components/ControlUnitDialog/index.tsx index 9344790023..55af3b746a 100644 --- a/frontend/src/features/ControlUnit/components/ControlUnitDialog/index.tsx +++ b/frontend/src/features/ControlUnit/components/ControlUnitDialog/index.tsx @@ -25,7 +25,7 @@ export function ControlUnitDialog() { if (!controlUnitId) { throw new FrontendError('`store.controlUnitDialog.controlUnitId` is undefined.') } - const healthcheckTextWarning = useMainAppSelector(store => store.global.healthcheckTextWarning) + const healthcheckTextWarning = useMainAppSelector(store => store.mainWindow.healthcheckTextWarning) const { data: controlUnit, error: getControlControlUnitError } = useGetControlUnitQuery( controlUnitId, diff --git a/frontend/src/features/ControlUnit/components/ControlUnitListMapButton.tsx b/frontend/src/features/ControlUnit/components/ControlUnitListMapButton.tsx index 075e630e9c..887171188b 100644 --- a/frontend/src/features/ControlUnit/components/ControlUnitListMapButton.tsx +++ b/frontend/src/features/ControlUnit/components/ControlUnitListMapButton.tsx @@ -11,8 +11,8 @@ export function ControlUnitListMapButton() { const wrapperRef = useRef(null) const dispatch = useMainAppDispatch() - // const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + // const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const isControlUnitDialogDisplayed = useMainAppSelector( state => state.displayedComponent.isControlUnitDialogDisplayed ) diff --git a/frontend/src/features/FleetSegment/useCases/addFleetSegmentYear.ts b/frontend/src/features/FleetSegment/useCases/addFleetSegmentYear.ts index c308087887..2fcdb1e2c6 100644 --- a/frontend/src/features/FleetSegment/useCases/addFleetSegmentYear.ts +++ b/frontend/src/features/FleetSegment/useCases/addFleetSegmentYear.ts @@ -1,7 +1,7 @@ import { addFleetSegmentYearFromAPI } from '@features/FleetSegment/apis' import { getFleetSegmentsYearEntries } from './getFleetSegmentsYearEntries' -import { setError } from '../../../domain/shared_slices/Global' +import { setError } from '../../MainWindow/slice' /** * Add a new fleet segment year diff --git a/frontend/src/features/FleetSegment/useCases/createFleetSegment.ts b/frontend/src/features/FleetSegment/useCases/createFleetSegment.ts index 483be2ac24..68529bde6e 100644 --- a/frontend/src/features/FleetSegment/useCases/createFleetSegment.ts +++ b/frontend/src/features/FleetSegment/useCases/createFleetSegment.ts @@ -1,6 +1,6 @@ import { createFleetSegmentFromAPI } from '@features/FleetSegment/apis' -import { setError } from '../../../domain/shared_slices/Global' +import { setError } from '../../MainWindow/slice' import type { FleetSegment, UpdateFleetSegment } from '../types' diff --git a/frontend/src/features/FleetSegment/useCases/deleteFleetSegment.ts b/frontend/src/features/FleetSegment/useCases/deleteFleetSegment.ts index 549e036b0f..9b5cb6925a 100644 --- a/frontend/src/features/FleetSegment/useCases/deleteFleetSegment.ts +++ b/frontend/src/features/FleetSegment/useCases/deleteFleetSegment.ts @@ -1,6 +1,6 @@ import { deleteFleetSegmentFromAPI } from '@features/FleetSegment/apis' -import { setError } from '../../../domain/shared_slices/Global' +import { setError } from '../../MainWindow/slice' import type { FleetSegment } from '../types' diff --git a/frontend/src/features/FleetSegment/useCases/getFleetSegmentsYearEntries.ts b/frontend/src/features/FleetSegment/useCases/getFleetSegmentsYearEntries.ts index fd33380c8d..004d90521a 100644 --- a/frontend/src/features/FleetSegment/useCases/getFleetSegmentsYearEntries.ts +++ b/frontend/src/features/FleetSegment/useCases/getFleetSegmentsYearEntries.ts @@ -1,6 +1,6 @@ import { getFleetSegmentYearEntriesFromAPI } from '@features/FleetSegment/apis' -import { setError } from '../../../domain/shared_slices/Global' +import { setError } from '../../MainWindow/slice' export const getFleetSegmentsYearEntries = () => dispatch => getFleetSegmentYearEntriesFromAPI().catch(error => { diff --git a/frontend/src/features/FleetSegment/useCases/updateFleetSegment.ts b/frontend/src/features/FleetSegment/useCases/updateFleetSegment.ts index 34657b26e7..c873765e1a 100644 --- a/frontend/src/features/FleetSegment/useCases/updateFleetSegment.ts +++ b/frontend/src/features/FleetSegment/useCases/updateFleetSegment.ts @@ -1,6 +1,6 @@ import { updateFleetSegmentFromAPI } from '@features/FleetSegment/apis' -import { setError } from '../../../domain/shared_slices/Global' +import { setError } from '../../MainWindow/slice' import type { FleetSegment, UpdateFleetSegment } from '../types' diff --git a/frontend/src/features/Healthcheck/components/HealthcheckHeadband.tsx b/frontend/src/features/Healthcheck/components/HealthcheckHeadband.tsx index 2257220ced..2bf84d8138 100644 --- a/frontend/src/features/Healthcheck/components/HealthcheckHeadband.tsx +++ b/frontend/src/features/Healthcheck/components/HealthcheckHeadband.tsx @@ -2,19 +2,19 @@ import { useEffect, useState } from 'react' import styled from 'styled-components' import { FIVE_MINUTES } from '../../../api/APIWorker' -import { setError, setHealthcheckTextWarning } from '../../../domain/shared_slices/Global' import { useMainAppDispatch } from '../../../hooks/useMainAppDispatch' import { useMainAppSelector } from '../../../hooks/useMainAppSelector' import { ChevronIcon } from '../../commonStyles/icons/ChevronIcon.style' import WarningSVG from '../../icons/Picto_alerte.svg?react' +import { setError, setHealthcheckTextWarning } from '../../MainWindow/slice' import { useGetHealthcheckQuery } from '../apis' import { useIsOnline } from '../hooks/useIsOnline' import { getHealthcheckWarnings } from '../utils' export function HealthcheckHeadband() { const dispatch = useMainAppDispatch() - const healthcheckTextWarning = useMainAppSelector(state => state.global.healthcheckTextWarning) - const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) + const healthcheckTextWarning = useMainAppSelector(state => state.mainWindow.healthcheckTextWarning) + const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) const isOnline = useIsOnline() const { data: healthcheck, diff --git a/frontend/src/features/InterestPoint/components/InterestPointMapButton/index.tsx b/frontend/src/features/InterestPoint/components/InterestPointMapButton/index.tsx index 81ff24dc5c..6313d6ddb1 100644 --- a/frontend/src/features/InterestPoint/components/InterestPointMapButton/index.tsx +++ b/frontend/src/features/InterestPoint/components/InterestPointMapButton/index.tsx @@ -1,3 +1,4 @@ +import { setRightMapBoxOpened } from '@features/MainWindow/slice' import { useEscapeFromKeyboardAndExecute } from '@hooks/useEscapeFromKeyboardAndExecute' import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { useMainAppSelector } from '@hooks/useMainAppSelector' @@ -6,14 +7,13 @@ import styled from 'styled-components' import { EditInterestPoint } from './EditInterestPoint' import { MapBox } from '../../../../domain/entities/map/constants' -import { setRightMapBoxOpened } from '../../../../domain/shared_slices/Global' import InterestPointSVG from '../../../icons/standardized/Landmark.svg?react' import { MapToolButton } from '../../../MainWindow/components/MapButtons/shared/MapToolButton' import { deleteInterestPointBeingDrawed, drawInterestPoint, endInterestPointDraw } from '../../slice' export function InterestPointMapButton() { const dispatch = useMainAppDispatch() - const { rightMapBoxOpened, rightMenuIsOpen } = useMainAppSelector(state => state.global) + const { rightMapBoxOpened, rightMenuIsOpen } = useMainAppSelector(state => state.mainWindow) const isRightMenuShrinked = !rightMenuIsOpen const isOpen = useMemo(() => rightMapBoxOpened === MapBox.INTEREST_POINT, [rightMapBoxOpened]) const wrapperRef = useRef(null) diff --git a/frontend/src/features/InterestPoint/layers/InterestPointLayer.jsx b/frontend/src/features/InterestPoint/layers/InterestPointLayer.jsx index b4c1a7ce32..cd65fad2e0 100644 --- a/frontend/src/features/InterestPoint/layers/InterestPointLayer.jsx +++ b/frontend/src/features/InterestPoint/layers/InterestPointLayer.jsx @@ -1,13 +1,19 @@ import { usePrevious } from '@mtes-mct/monitor-ui' -import { useEffect, useRef, useState } from 'react' - -import { useDispatch, useSelector } from 'react-redux' -import VectorSource from 'ol/source/Vector' -import { MapBox, OPENLAYERS_PROJECTION } from '../../../domain/entities/map/constants' +import GeoJSON from 'ol/format/GeoJSON' +import LineString from 'ol/geom/LineString' import Draw from 'ol/interaction/Draw' import VectorLayer from 'ol/layer/Vector' -import { getInterestPointStyle, POIStyle } from './interestPoint.style' +import { getLength } from 'ol/sphere' +import { useEffect, useRef, useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' import { v4 as uuidv4 } from 'uuid' + +import { getInterestPointStyle, POIStyle } from './interestPoint.style' +import { InterestPointLine } from './interestPointLine' +import { LayerProperties } from '../../../domain/entities/layers/constants' +import { MapBox, OPENLAYERS_PROJECTION } from '../../../domain/entities/map/constants' +import saveInterestPointFeature from '../../../domain/use_cases/interestPoint/saveInterestPointFeature' +import { monitorfishMap } from '../../map/monitorfishMap' import { InterestPointOverlay } from '../components/InterestPointOverlay' import { deleteInterestPointBeingDrawed, @@ -18,19 +24,7 @@ import { updateInterestPointBeingDrawed, updateInterestPointKeyBeingDrawed } from '../slice' -import { - coordinatesAreModified, - coordinatesOrTypeAreModified, - InterestPointType -} from '../utils' -import saveInterestPointFeature from '../../../domain/use_cases/interestPoint/saveInterestPointFeature' -import GeoJSON from 'ol/format/GeoJSON' -import LineString from 'ol/geom/LineString' -import { InterestPointLine } from './interestPointLine' -import { getLength } from 'ol/sphere' -import { LayerProperties } from '../../../domain/entities/layers/constants' -import { setRightMapBoxOpened } from '../../../domain/shared_slices/Global' -import { monitorfishMap } from '../../map/monitorfishMap' +import { coordinatesAreModified, coordinatesOrTypeAreModified, InterestPointType } from '../utils' const DRAW_START_EVENT = 'drawstart' const DRAW_ABORT_EVENT = 'drawabort' @@ -38,44 +32,46 @@ const DRAW_END_EVENT = 'drawend' export const MIN_ZOOM = 7 -const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { +function InterestPointLayer({ mapMovingAndZoomEvent }) { const dispatch = useDispatch() const { - isDrawing, - isEditing, - /** @type {InterestPoint | null} interestPointBeingDrawed */ interestPointBeingDrawed, - /** @type {InterestPoint[]} interestPoints */ interestPoints, + /** @type {InterestPoint | null} interestPointBeingDrawed */ + isDrawing, + /** @type {InterestPoint[]} interestPoints */ + isEditing, triggerInterestPointFeatureDeletion } = useSelector(state => state.interestPoint) const [drawObject, setDrawObject] = useState(null) const vectorSourceRef = useRef(null) - function getVectorSource () { + function getVectorSource() { if (vectorSourceRef.current === null) { vectorSourceRef.current = new VectorSource({ - wrapX: false, - projection: OPENLAYERS_PROJECTION + projection: OPENLAYERS_PROJECTION, + wrapX: false }) } + return vectorSourceRef.current } const layerRef = useRef(null) - function getLayer () { + function getLayer() { if (layerRef.current === null) { layerRef.current = new VectorLayer({ - source: getVectorSource(), renderBuffer: 7, + source: getVectorSource(), + style: (feature, resolution) => getInterestPointStyle(feature, resolution), updateWhileAnimating: true, updateWhileInteracting: true, - style: (feature, resolution) => getInterestPointStyle(feature, resolution), zIndex: LayerProperties.INTEREST_POINT.zIndex }) } + return layerRef.current } @@ -84,7 +80,7 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { const previousInterestPointBeingDrawed = usePrevious(interestPointBeingDrawed) useEffect(() => { - function addLayerToMap () { + function addLayerToMap() { monitorfishMap.getLayers().push(getLayer()) return () => { @@ -96,22 +92,24 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { }, []) useEffect(() => { - function drawExistingFeaturesOnMap () { + function drawExistingFeaturesOnMap() { if (interestPoints) { - const features = interestPoints.map(interestPoint => { - if (interestPoint.feature) { - const nextFeature = new GeoJSON({ - featureProjection: OPENLAYERS_PROJECTION - }).readFeature(interestPoint.feature) + const features = interestPoints + .map(interestPoint => { + if (interestPoint.feature) { + const nextFeature = new GeoJSON({ + featureProjection: OPENLAYERS_PROJECTION + }).readFeature(interestPoint.feature) - const { feature, ...interestPointWithoutFeature } = interestPoint - nextFeature.setProperties(interestPointWithoutFeature) + const { feature, ...interestPointWithoutFeature } = interestPoint + nextFeature.setProperties(interestPointWithoutFeature) - return nextFeature - } + return nextFeature + } - return null - }).filter(feature => feature) + return null + }) + .filter(feature => feature) getVectorSource().addFeatures(features) } @@ -122,21 +120,23 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { useEffect(() => { if (isDrawing) { - function addEmptyNextInterestPoint () { - dispatch(updateInterestPointBeingDrawed({ - uuid: uuidv4(), - name: null, - type: InterestPointType.FISHING_VESSEL, - coordinates: null, - observations: null - })) + function addEmptyNextInterestPoint() { + dispatch( + updateInterestPointBeingDrawed({ + coordinates: null, + name: null, + observations: null, + type: InterestPointType.FISHING_VESSEL, + uuid: uuidv4() + }) + ) } - function drawNewFeatureOnMap () { + function drawNewFeatureOnMap() { const draw = new Draw({ source: getVectorSource(), - type: 'Point', - style: POIStyle + style: POIStyle, + type: 'Point' }) monitorfishMap.addInteraction(draw) @@ -149,11 +149,11 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { }, [isDrawing]) useEffect(() => { - function removeInteraction () { + function removeInteraction() { if (!isDrawing && drawObject) { setDrawObject(null) - function waitForUnwantedZoomAndQuitInteraction () { + function waitForUnwantedZoomAndQuitInteraction() { setTimeout(() => { monitorfishMap.removeInteraction(drawObject) }, 300) @@ -167,17 +167,19 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { }, [isDrawing]) useEffect(() => { - function handleDrawEvents () { + function handleDrawEvents() { if (drawObject) { drawObject.once(DRAW_START_EVENT, event => { - function startDrawing (event, type) { - dispatch(updateInterestPointBeingDrawed({ - uuid: interestPointBeingDrawed.uuid, - name: null, - type: type, - coordinates: event.feature.getGeometry().getLastCoordinate(), - observations: null - })) + function startDrawing(event, type) { + dispatch( + updateInterestPointBeingDrawed({ + coordinates: event.feature.getGeometry().getLastCoordinate(), + name: null, + observations: null, + type, + uuid: interestPointBeingDrawed.uuid + }) + ) } if (interestPointBeingDrawed) { @@ -202,7 +204,7 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { }, [drawObject, interestPointBeingDrawed]) useEffect(() => { - function showOrHideInterestPointsOverlays () { + function showOrHideInterestPointsOverlays() { const currentZoom = monitorfishMap.getView().getZoom().toFixed(2) if (currentZoom !== previousMapZoom.current) { previousMapZoom.current = currentZoom @@ -229,7 +231,7 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { }, [triggerInterestPointFeatureDeletion]) useEffect(() => { - function modifyFeatureWhenCoordinatesOrTypeModified () { + function modifyFeatureWhenCoordinatesOrTypeModified() { if (interestPointBeingDrawed?.coordinates?.length && interestPointBeingDrawed?.uuid) { const drawingFeatureToUpdate = getVectorSource().getFeatureById(interestPointBeingDrawed.uuid) @@ -238,13 +240,16 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { drawingFeatureToUpdate.getGeometry().setCoordinates(interestPointWithoutFeature.coordinates) drawingFeatureToUpdate.setProperties(interestPointWithoutFeature) - const nextFeature = new GeoJSON() - .writeFeatureObject(drawingFeatureToUpdate, { featureProjection: OPENLAYERS_PROJECTION }) + const nextFeature = new GeoJSON().writeFeatureObject(drawingFeatureToUpdate, { + featureProjection: OPENLAYERS_PROJECTION + }) - dispatch(updateInterestPointKeyBeingDrawed({ - key: 'feature', - value: nextFeature - })) + dispatch( + updateInterestPointKeyBeingDrawed({ + key: 'feature', + value: nextFeature + }) + ) } } } @@ -253,9 +258,16 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { }, [interestPointBeingDrawed?.coordinates, interestPointBeingDrawed?.type]) useEffect(() => { - function initLineWhenInterestPointCoordinatesModified () { - if (interestPointBeingDrawed && previousInterestPointBeingDrawed && coordinatesAreModified(interestPointBeingDrawed, previousInterestPointBeingDrawed)) { - const line = new LineString([interestPointBeingDrawed.coordinates, previousInterestPointBeingDrawed.coordinates]) + function initLineWhenInterestPointCoordinatesModified() { + if ( + interestPointBeingDrawed && + previousInterestPointBeingDrawed && + coordinatesAreModified(interestPointBeingDrawed, previousInterestPointBeingDrawed) + ) { + const line = new LineString([ + interestPointBeingDrawed.coordinates, + previousInterestPointBeingDrawed.coordinates + ]) const distance = getLength(line, { projection: OPENLAYERS_PROJECTION }) if (distance > 10) { @@ -264,7 +276,9 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { interestPointToCoordinates.delete(featureId) const feature = getVectorSource().getFeatureById(featureId) if (feature) { - feature.setGeometry(new LineString([interestPointBeingDrawed.coordinates, interestPointBeingDrawed.coordinates])) + feature.setGeometry( + new LineString([interestPointBeingDrawed.coordinates, interestPointBeingDrawed.coordinates]) + ) } } } @@ -274,7 +288,7 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { initLineWhenInterestPointCoordinatesModified() }, [interestPointBeingDrawed]) - function deleteInterestPoint (uuid) { + function deleteInterestPoint(uuid) { const feature = getVectorSource().getFeatureById(uuid) if (feature) { getVectorSource().removeFeature(feature) @@ -290,7 +304,7 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { dispatch(removeInterestPoint(uuid)) } - function moveInterestPointLine (uuid, coordinates, nextCoordinates, offset) { + function moveInterestPointLine(uuid, coordinates, nextCoordinates, offset) { const featureId = InterestPointLine.getFeatureId(uuid) if (interestPointToCoordinates.has(featureId)) { @@ -299,14 +313,13 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { if (existingLabelLineFeature) { if (interestPointFeature) { - existingLabelLineFeature.setGeometry(new LineString([interestPointFeature.getGeometry().getCoordinates(), nextCoordinates])) + existingLabelLineFeature.setGeometry( + new LineString([interestPointFeature.getGeometry().getCoordinates(), nextCoordinates]) + ) } } } else { - const interestPointLineFeature = InterestPointLine.getFeature( - coordinates, - nextCoordinates, - featureId) + const interestPointLineFeature = InterestPointLine.getFeature(coordinates, nextCoordinates, featureId) getVectorSource().addFeature(interestPointLineFeature) } @@ -316,12 +329,12 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { setInterestPointToCoordinates(nextVesselToCoordinates) } - function modifyInterestPoint (uuid) { + function modifyInterestPoint(uuid) { dispatch(editInterestPoint(uuid)) dispatch(setRightMapBoxOpened(MapBox.INTEREST_POINT)) } - function deleteInterestPointBeingDrawedAndCloseTool () { + function deleteInterestPointBeingDrawedAndCloseTool() { dispatch(endInterestPointDraw()) dispatch(setRightMapBoxOpened(undefined)) dispatch(deleteInterestPointBeingDrawed()) @@ -330,41 +343,37 @@ const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { return ( <>
- { - interestPoints && Array.isArray(interestPoints) - ? interestPoints.map(interestPoint => { - return ( + - }) - : null - } - { - interestPointBeingDrawed && !isEditing - ? {}} - zoomHasChanged={previousMapZoom.current} - moveLine={moveInterestPointLine} - /> - : null - } + )) + : null} + {interestPointBeingDrawed && !isEditing ? ( + {}} + moveLine={moveInterestPointLine} + name={interestPointBeingDrawed.name} + observations={interestPointBeingDrawed.observations} + uuid={interestPointBeingDrawed.uuid} + zoomHasChanged={previousMapZoom.current} + /> + ) : null}
) diff --git a/frontend/src/features/LayersSidebar/components/index.tsx b/frontend/src/features/LayersSidebar/components/index.tsx index 323a1c326f..1e258576b6 100644 --- a/frontend/src/features/LayersSidebar/components/index.tsx +++ b/frontend/src/features/LayersSidebar/components/index.tsx @@ -6,12 +6,12 @@ import styled from 'styled-components' import { NamespaceContext } from '../../../context/NamespaceContext' import { MapBox } from '../../../domain/entities/map/constants' -import { setLeftMapBoxOpened } from '../../../domain/shared_slices/Global' import { AdministrativeZones } from '../../AdministrativeZone/components/AdministrativeZones' import { BaseMaps } from '../../BaseMap/components/BaseMaps' import { MapComponent } from '../../commonStyles/MapComponent' import { CustomZones } from '../../CustomZone/components/CustomZones' import { MapButton } from '../../MainWindow/components/MapButtons/MapButton' +import { setLeftMapBoxOpened } from '../../MainWindow/slice' import { RegulationSearch } from '../../Regulation/components/RegulationSearch' import { RegulatoryZoneMetadata } from '../../Regulation/components/RegulatoryZoneMetadata' import { RegulatoryZones } from '../../Regulation/components/RegulatoryZones' @@ -22,9 +22,9 @@ export function LayersSidebar() { const regulatoryZoneMetadataPanelIsOpen = useMainAppSelector( state => state.regulatory.regulatoryZoneMetadataPanelIsOpen ) - const healthcheckTextWarning = useMainAppSelector(state => state.global.healthcheckTextWarning) - const leftMapBoxOpened = useMainAppSelector(state => state.global.leftMapBoxOpened) - const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) + const healthcheckTextWarning = useMainAppSelector(state => state.mainWindow.healthcheckTextWarning) + const leftMapBoxOpened = useMainAppSelector(state => state.mainWindow.leftMapBoxOpened) + const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) useEffect(() => { if (leftMapBoxOpened !== MapBox.REGULATIONS) { diff --git a/frontend/src/features/Logbook/useCases/getVesselLogbook.ts b/frontend/src/features/Logbook/useCases/getVesselLogbook.ts index df14b9444d..3733a9914b 100644 --- a/frontend/src/features/Logbook/useCases/getVesselLogbook.ts +++ b/frontend/src/features/Logbook/useCases/getVesselLogbook.ts @@ -4,10 +4,10 @@ import { customDayjs } from '@mtes-mct/monitor-ui' import { vesselsAreEquals } from '../../../domain/entities/vessel/vessel' import { getTrackRequestFromDates } from '../../../domain/entities/vesselTrackDepth' import { displayedErrorActions } from '../../../domain/shared_slices/DisplayedError' -import { removeError, setError } from '../../../domain/shared_slices/Global' import { displayOrLogError } from '../../../domain/use_cases/error/displayOrLogError' import { updateSelectedVesselTrackRequest } from '../../../domain/use_cases/vessel/updateSelectedVesselTrackRequest' import NoLogbookMessagesFoundError from '../../../errors/NoLogbookMessagesFoundError' +import { removeError, setError } from '../../MainWindow/slice' import { getVesselLogbookFromAPI } from '../api' import { NavigateTo } from '../constants' import { logbookActions } from '../slice' diff --git a/frontend/src/features/MainWindow/components/LeftMenu.tsx b/frontend/src/features/MainWindow/components/LeftMenu.tsx new file mode 100644 index 0000000000..643b921e75 --- /dev/null +++ b/frontend/src/features/MainWindow/components/LeftMenu.tsx @@ -0,0 +1,156 @@ +import { openSideWindowPath } from '@features/SideWindow/useCases/openSideWindowPath' +import { useIsSuperUser } from '@hooks/authorization/useIsSuperUser' +import { useMainAppDispatch } from '@hooks/useMainAppDispatch' +import { useMainAppSelector } from '@hooks/useMainAppSelector' +import { Icon, IconButton, Size } from '@mtes-mct/monitor-ui' +import { assertNotNullish } from '@utils/assertNotNullish' +import { MapBox } from 'domain/entities/map/constants' +import { SideWindowMenuKey, SideWindowStatus } from 'domain/entities/sideWindow/constants' +import { sideWindowActions } from 'domain/shared_slices/SideWindow' +import { useRef } from 'react' +import styled from 'styled-components' + +import { mainWindowActions } from '../slice' + +export function LeftMenu() { + const missionButtonRef = useRef(null) + + const dispatch = useMainAppDispatch() + const { favorites } = useMainAppSelector(state => state.favoriteVessel) + const leftDialog = useMainAppSelector(state => state.mainWindow.leftDialog) + const isAlertsMapButtonDisplayed = useMainAppSelector(state => state.displayedComponent.isAlertsMapButtonDisplayed) + const isBeaconMalfunctionsMapButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isBeaconMalfunctionsMapButtonDisplayed + ) + const isFavoriteVesselsMapButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isFavoriteVesselsMapButtonDisplayed + ) + const isMissionsMapButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isMissionsMapButtonDisplayed + ) + const isSuperUser = useIsSuperUser() + // const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) + const sideWindow = useMainAppSelector(state => state.sideWindow) + + const toggleMissionMenuDialog = () => { + assertNotNullish(missionButtonRef.current) + + dispatch( + mainWindowActions.toggleLeftDialog({ + key: MapBox.MISSIONS, + topPosition: missionButtonRef.current.getBoundingClientRect().top + }) + ) + } + + const toggleSideWindowAlertList = () => { + const isActive = + sideWindow.status !== SideWindowStatus.CLOSED && + sideWindow.selectedPath.menu === SideWindowMenuKey.ALERT_LIST_AND_REPORTING_LIST + if (isActive) { + dispatch(sideWindowActions.close()) + + return + } + + dispatch(openSideWindowPath({ menu: SideWindowMenuKey.ALERT_LIST_AND_REPORTING_LIST })) + } + + return ( + + + + + + {isFavoriteVesselsMapButtonDisplayed && ( + + + + {favorites?.length || 0} + + + + + )} + + + {isSuperUser && isMissionsMapButtonDisplayed && ( + + + + )} + + {isSuperUser && isAlertsMapButtonDisplayed && ( + + )} + + {import.meta.env.FRONTEND_PRIOR_NOTIFICATION_LIST_ENABLED === 'true' && ( + + )} + + {isSuperUser && isBeaconMalfunctionsMapButtonDisplayed && } + + + ) +} + +const Wrapper = styled.div` + box-sizing: border-box; + display: flex; + flex-direction: column; + position: absolute; + left: 112px; + top: 12px; + + * { + box-sizing: border-box; + } + + > div:not(:first-child) { + margin-top: 16px; + } +` + +const Block = styled.div` + display: flex; + flex-direction: column; + + > *:not(:first-child) { + margin-top: 4px; + } +` + +const IconButtonWrapper = styled.div` + position: relative; +` +const IconButtonBadge = styled.div<{ + $isActive: boolean +}>` + background-color: ${p => (p.$isActive ? p.theme.color.charcoal : p.theme.color.gainsboro)}; + border-radius: 50%; + color: ${p => (p.$isActive ? p.theme.color.white : p.theme.color.gunMetal)}; + height: 16px; + left: 40px; + line-height: 16px; + position: absolute; + top: -6px; + width: 16px; + z-index: 100; +` diff --git a/frontend/src/features/MainWindow/components/MapButtons/AlertsMapButton.tsx b/frontend/src/features/MainWindow/components/MapButtons/AlertsMapButton.tsx deleted file mode 100644 index 998850eed3..0000000000 --- a/frontend/src/features/MainWindow/components/MapButtons/AlertsMapButton.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { sideWindowActions } from '@features/SideWindow/slice' -import { openSideWindowPath } from '@features/SideWindow/useCases/openSideWindowPath' -import { useMainAppDispatch } from '@hooks/useMainAppDispatch' -import { useMainAppSelector } from '@hooks/useMainAppSelector' -import { useCallback } from 'react' -import styled from 'styled-components' - -import { MapButton } from './MapButton' -import { SideWindowMenuKey, SideWindowStatus } from '../../../../domain/entities/sideWindow/constants' -import AlertsSVG from '../../../icons/Icone_alertes.svg?react' - -export function AlertsMapButton() { - const dispatch = useMainAppDispatch() - const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) - const sideWindow = useMainAppSelector(state => state.sideWindow) - - const isActive = - sideWindow.status !== SideWindowStatus.CLOSED && - sideWindow.selectedPath.menu === SideWindowMenuKey.ALERT_LIST_AND_REPORTING_LIST - - const toggleSideWindow = useCallback(() => { - if (isActive) { - dispatch(sideWindowActions.close()) - - return - } - - dispatch(openSideWindowPath({ menu: SideWindowMenuKey.ALERT_LIST_AND_REPORTING_LIST })) - }, [dispatch, isActive]) - - return ( - - - - ) -} - -const AlertsButton = styled(MapButton)<{ - $isActive: boolean -}>` - position: absolute; - display: inline-block; - background: ${p => (p.$isActive ? p.theme.color.blueGray : p.theme.color.charcoal)}; - padding: 2px 2px 2px 2px; - top: 184px; - left: 10px; - border-radius: 2px; - height: 40px; - width: 40px; - - &:hover, - &:focus { - background: ${p => (p.$isActive ? p.theme.color.blueGray : p.theme.color.charcoal)}; - } -` - -const AlertsIcon = styled(AlertsSVG)` - margin-top: 5px; - width: 20px; -` diff --git a/frontend/src/features/MainWindow/components/MapButtons/BeaconMalfunctionsMapButton.tsx b/frontend/src/features/MainWindow/components/MapButtons/BeaconMalfunctionsMapButton.tsx index c1a48d7611..e9284ed4b9 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/BeaconMalfunctionsMapButton.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/BeaconMalfunctionsMapButton.tsx @@ -11,7 +11,7 @@ import BeaconMalfunctionsSVG from '../../../icons/Icone_VMS.svg?react' export function BeaconMalfunctionsMapButton() { const dispatch = useMainAppDispatch() - const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) + const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) const sideWindow = useMainAppSelector(state => state.sideWindow) const isActive = diff --git a/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx b/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx index f1c0b43cec..013d92d7e6 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx @@ -2,7 +2,6 @@ import { COLORS } from '@constants/constants' import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { useMainAppSelector } from '@hooks/useMainAppSelector' import { MapBox } from 'domain/entities/map/constants' -import { setLeftMapBoxOpened } from 'domain/shared_slices/Global' import { useRef } from 'react' import styled from 'styled-components' @@ -14,6 +13,7 @@ import { MapComponent } from '../../../../commonStyles/MapComponent' import HidingOtherTracksSVG from '../../../../icons/Bouton_masquer_pistes_actif.svg?react' import ShowingOtherTracksSVG from '../../../../icons/Bouton_masquer_pistes_inactif.svg?react' import FavoriteSVG from '../../../../icons/favorite.svg?react' +import { setLeftMapBoxOpened } from '../../../slice' import { MapButton } from '../MapButton' export function FavoriteVessels() { @@ -22,8 +22,8 @@ export function FavoriteVessels() { const { hideNonSelectedVessels, selectedVesselIdentity, vesselsTracksShowed } = useMainAppSelector( state => state.vessel ) - const leftMapBoxOpened = useMainAppSelector(state => state.global.leftMapBoxOpened) - const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) + const leftMapBoxOpened = useMainAppSelector(state => state.mainWindow.leftMapBoxOpened) + const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) const wrapperRef = useRef(null) diff --git a/frontend/src/features/MainWindow/components/MapButtons/MapButton.tsx b/frontend/src/features/MainWindow/components/MapButtons/MapButton.tsx index 2c5ba8c777..57f05244c4 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/MapButton.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/MapButton.tsx @@ -1,4 +1,3 @@ -import { useMainAppSelector } from '@hooks/useMainAppSelector' import styled from 'styled-components' import type { HTMLProps, ReactNode } from 'react' @@ -8,8 +7,6 @@ type MapButtonType = { isHidden?: boolean | undefined } & HTMLProps export function MapButton({ children, isHidden, ...props }: MapButtonType) { - const healthcheckTextWarning = useMainAppSelector(state => state.global.healthcheckTextWarning) - return ( /** * TODO We have this error without the `ts-ignore` : @@ -18,7 +15,7 @@ export function MapButton({ children, isHidden, ...props }: MapButtonType) { */ /* eslint-disable react/jsx-props-no-spreading */ // @ts-ignore - + {children} /* eslint-enable react/jsx-props-no-spreading */ @@ -26,9 +23,7 @@ export function MapButton({ children, isHidden, ...props }: MapButtonType) { } const Wrapper = styled.button<{ - $hasHealthcheckTextWarning?: boolean | undefined $isHidden?: boolean | undefined }>` - margin-top: ${p => (p.$hasHealthcheckTextWarning ? 50 : 0)}px; visibility: ${p => (p.$isHidden ? 'hidden' : 'visible')}; ` diff --git a/frontend/src/features/MainWindow/components/MapButtons/Missions/index.tsx b/frontend/src/features/MainWindow/components/MapButtons/Missions/index.tsx deleted file mode 100644 index a558740a0d..0000000000 --- a/frontend/src/features/MainWindow/components/MapButtons/Missions/index.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import { COLORS } from '@constants/constants' -import { addMission } from '@features/Mission/useCases/addMission' -import { openSideWindowPath } from '@features/SideWindow/useCases/openSideWindowPath' -import { useMainAppDispatch } from '@hooks/useMainAppDispatch' -import { useMainAppSelector } from '@hooks/useMainAppSelector' -import { Accent, Button, Icon, IconButton, Size, THEME } from '@mtes-mct/monitor-ui' -import { useCallback } from 'react' -import styled from 'styled-components' - -import { MapBox } from '../../../../../domain/entities/map/constants' -import { SideWindowMenuKey, SideWindowStatus } from '../../../../../domain/entities/sideWindow/constants' -import { setDisplayedComponents } from '../../../../../domain/shared_slices/DisplayedComponent' -import { setLeftMapBoxOpened } from '../../../../../domain/shared_slices/Global' -import { sideWindowActions } from '../../../../SideWindow/slice' -import { MapToolBox } from '../shared/MapToolBox' -import { MapToolButton } from '../shared/MapToolButton' - -export function MissionsMenu() { - const dispatch = useMainAppDispatch() - const sideWindow = useMainAppSelector(state => state.sideWindow) - const leftMapBoxOpened = useMainAppSelector(state => state.global.leftMapBoxOpened) - const isMissionsLayerDisplayed = useMainAppSelector(state => state.displayedComponent.isMissionsLayerDisplayed) - - const isActive = - sideWindow.status !== SideWindowStatus.CLOSED && sideWindow.selectedPath.menu === SideWindowMenuKey.MISSION_LIST - - const toggleMissionsWindow = useCallback(() => { - if (isActive) { - dispatch(sideWindowActions.close()) - - return - } - - dispatch(openSideWindowPath({ menu: SideWindowMenuKey.MISSION_LIST })) - }, [dispatch, isActive]) - - const openNewMission = () => { - dispatch(addMission()) - } - - const toggleMissionsMenu = () => { - dispatch(setLeftMapBoxOpened(leftMapBoxOpened === MapBox.MISSIONS ? undefined : MapBox.MISSIONS)) - } - - const toggleMissionsLayer = () => { - dispatch(setDisplayedComponents({ isMissionsLayerDisplayed: !isMissionsLayerDisplayed })) - } - - return ( - - - - - - Missions et contrôles - - - -
- - Ouvrir une nouvelle mission - -
-
- - Voir la vue détaillée des missions - -
-
-
-
- - - -
- ) -} - -const Wrapper = styled.div` - transition: all 0.2s; - z-index: 98; - left: 10px; -` - -const MissionMenuBox = styled(MapToolBox)` - top: 136px; -` - -const MissionMenuButton = styled(MapToolButton)`` - -const MissionsMenuWrapper = styled.div` - width: 320px; - background-color: ${COLORS.white}; -` - -const MissionsMenuHeader = styled.div` - height: 40px; - background-color: ${COLORS.charcoal}; - display: flex; - justify-content: space-between; - padding-right: 5px; - padding-left: 5px; - align-items: center; -` - -const Title = styled.span` - font-size: 16px; - line-height: 22px; - color: ${COLORS.white}; -` - -const MissionsMenuBody = styled.div`` -const Section = styled.div` - padding: 12px; - &:not(:last-child) { - border-bottom: 1px solid ${COLORS.gainsboro}; - } -` - -const ToggleMissionsButton = styled(IconButton)` - background: ${COLORS.white}; - - &:hover { - background: ${COLORS.white}; - } - &:focus { - background: ${COLORS.white}; - } -` -const ToggleMissionMenuButton = styled(IconButton)` - color: white; -` -const BlockIconButton = styled(Button)` - width: 100%; -` diff --git a/frontend/src/features/MainWindow/components/MapButtons/VesselFilters/Filters.tsx b/frontend/src/features/MainWindow/components/MapButtons/VesselFilters/Filters.tsx index 31eb8a0b3c..7d97740280 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/VesselFilters/Filters.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/VesselFilters/Filters.tsx @@ -19,7 +19,7 @@ import { MapToolBox } from '../shared/MapToolBox' export function Filters() { const dispatch = useMainAppDispatch() const { filters, nonFilteredVesselsAreHidden } = useMainAppSelector(state => state.filter) - const rightMapBoxOpened = useMainAppSelector(state => state.global.rightMapBoxOpened) + const rightMapBoxOpened = useMainAppSelector(state => state.mainWindow.rightMapBoxOpened) const isOpen = useMemo(() => rightMapBoxOpened === MapBox.FILTERS, [rightMapBoxOpened]) diff --git a/frontend/src/features/MainWindow/components/MapButtons/VesselFilters/index.tsx b/frontend/src/features/MainWindow/components/MapButtons/VesselFilters/index.tsx index 4807a10253..8bb951953f 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/VesselFilters/index.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/VesselFilters/index.tsx @@ -7,16 +7,16 @@ import styled from 'styled-components' import { Filters } from './Filters' import { MapBox } from '../../../../../domain/entities/map/constants' -import { setRightMapBoxOpened } from '../../../../../domain/shared_slices/Global' import FilterSVG from '../../../../icons/standardized/Filter.svg?react' +import { setRightMapBoxOpened } from '../../../slice' import { MapToolButton } from '../shared/MapToolButton' export function VesselFiltersMapButton() { const dispatch = useMainAppDispatch() const filters = useMainAppSelector(state => state.filter.filters) const previousFilters = usePrevious(filters) - const rightMapBoxOpened = useMainAppSelector(state => state.global.rightMapBoxOpened) - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const rightMapBoxOpened = useMainAppSelector(state => state.mainWindow.rightMapBoxOpened) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const isRightMenuShrinked = !rightMenuIsOpen const isOpen = useMemo(() => rightMapBoxOpened === MapBox.FILTERS, [rightMapBoxOpened]) diff --git a/frontend/src/features/MainWindow/components/MapButtons/VesselLabels/EditVesselLabels.tsx b/frontend/src/features/MainWindow/components/MapButtons/VesselLabels/EditVesselLabels.tsx index 960dd02676..5610558b59 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/VesselLabels/EditVesselLabels.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/VesselLabels/EditVesselLabels.tsx @@ -24,7 +24,7 @@ export function EditVesselLabels() { const vesselLabel = useMainAppSelector(state => state.map.vesselLabel) const riskFactorShowedOnMap = useMainAppSelector(state => state.map.riskFactorShowedOnMap) const vesselLabelsShowedOnMap = useMainAppSelector(state => state.map.vesselLabelsShowedOnMap) - const rightMapBoxOpened = useMainAppSelector(state => state.global.rightMapBoxOpened) + const rightMapBoxOpened = useMainAppSelector(state => state.mainWindow.rightMapBoxOpened) const isOpen = useMemo(() => rightMapBoxOpened === MapBox.VESSEL_LABELS, [rightMapBoxOpened]) diff --git a/frontend/src/features/MainWindow/components/MapButtons/VesselLabels/index.tsx b/frontend/src/features/MainWindow/components/MapButtons/VesselLabels/index.tsx index 02390ea1a0..78d30967dd 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/VesselLabels/index.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/VesselLabels/index.tsx @@ -7,13 +7,13 @@ import styled from 'styled-components' import { EditVesselLabels } from './EditVesselLabels' import { MapBox } from '../../../../../domain/entities/map/constants' -import { setRightMapBoxOpened } from '../../../../../domain/shared_slices/Global' +import { setRightMapBoxOpened } from '../../../slice' import { MapToolButton } from '../shared/MapToolButton' export function VesselLabelsMapButton() { const dispatch = useMainAppDispatch() - const rightMapBoxOpened = useMainAppSelector(state => state.global.rightMapBoxOpened) - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const rightMapBoxOpened = useMainAppSelector(state => state.mainWindow.rightMapBoxOpened) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const isRightMenuShrinked = !rightMenuIsOpen const isOpen = useMemo(() => rightMapBoxOpened === MapBox.VESSEL_LABELS, [rightMapBoxOpened]) diff --git a/frontend/src/features/MainWindow/components/MapButtons/VesselVisibility/EditVesselVisibility.tsx b/frontend/src/features/MainWindow/components/MapButtons/VesselVisibility/EditVesselVisibility.tsx index 6c7cc3241f..61bcd0cc44 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/VesselVisibility/EditVesselVisibility.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/VesselVisibility/EditVesselVisibility.tsx @@ -25,7 +25,7 @@ import { Header, Content } from '../shared/styles' export function EditVesselVisibility() { const dispatch = useMainAppDispatch() const hideNonSelectedVessels = useMainAppSelector(state => state.vessel.hideNonSelectedVessels) - const rightMapBoxOpened = useMainAppSelector(state => state.global.rightMapBoxOpened) + const rightMapBoxOpened = useMainAppSelector(state => state.mainWindow.rightMapBoxOpened) const hideVesselsAtPort = useMainAppSelector(state => state.map.hideVesselsAtPort) const defaultVesselTrackDepth = useMainAppSelector(state => state.map.defaultVesselTrackDepth) const showingVesselsEstimatedPositions = useMainAppSelector(state => state.map.showingVesselsEstimatedPositions) diff --git a/frontend/src/features/MainWindow/components/MapButtons/VesselVisibility/index.tsx b/frontend/src/features/MainWindow/components/MapButtons/VesselVisibility/index.tsx index b49f15b116..697726005d 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/VesselVisibility/index.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/VesselVisibility/index.tsx @@ -7,13 +7,13 @@ import styled from 'styled-components' import { EditVesselVisibility } from './EditVesselVisibility' import { MapBox } from '../../../../../domain/entities/map/constants' -import { setRightMapBoxOpened } from '../../../../../domain/shared_slices/Global' +import { setRightMapBoxOpened } from '../../../slice' import { MapToolButton } from '../shared/MapToolButton' export function VesselVisibilityMapButton() { const dispatch = useMainAppDispatch() - const rightMapBoxOpened = useMainAppSelector(state => state.global.rightMapBoxOpened) - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const rightMapBoxOpened = useMainAppSelector(state => state.mainWindow.rightMapBoxOpened) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const isRightMenuShrinked = !rightMenuIsOpen const isOpen = useMemo(() => rightMapBoxOpened === MapBox.VESSEL_VISIBILITY, [rightMapBoxOpened]) diff --git a/frontend/src/features/MainWindow/components/MapButtons/index.tsx b/frontend/src/features/MainWindow/components/MapButtons/index.tsx index d15f291697..c513bdc972 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/index.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/index.tsx @@ -3,10 +3,8 @@ import { ControlUnitListMapButton } from '@features/ControlUnit/components/Contr import { useMainAppSelector } from '@hooks/useMainAppSelector' import { LegacyRsuiteComponentsWrapper } from 'ui/LegacyRsuiteComponentsWrapper' -import { AlertsMapButton } from './AlertsMapButton' import { BeaconMalfunctionsMapButton } from './BeaconMalfunctionsMapButton' import { FavoriteVessels } from './FavoriteVessels' -import { MissionsMenu } from './Missions' import { VesselFiltersMapButton } from './VesselFilters' import { VesselLabelsMapButton } from './VesselLabels' import { VesselVisibilityMapButton } from './VesselVisibility' @@ -17,7 +15,6 @@ import { PriorNotificationListButton } from '../../../PriorNotification/componen export function MapButtons() { const isSuperUser = useIsSuperUser() - const isAlertsMapButtonDisplayed = useMainAppSelector(state => state.displayedComponent.isAlertsMapButtonDisplayed) const isAccountMapButtonDisplayed = useMainAppSelector(state => state.displayedComponent.isAccountMapButtonDisplayed) const isPriorNotificationMapButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isPriorNotificationMapButtonDisplayed @@ -51,8 +48,6 @@ export function MapButtons() { <> {isFavoriteVesselsMapButtonDisplayed && } - {isSuperUser && isFavoriteVesselsMapButtonDisplayed && } - {isSuperUser && isAlertsMapButtonDisplayed && } {(isSuperUser || import.meta.env.FRONTEND_PRIOR_NOTIFICATION_LIST_ENABLED === 'true') && isPriorNotificationMapButtonDisplayed && } {isSuperUser && isBeaconMalfunctionsMapButtonDisplayed && } diff --git a/frontend/src/features/MainWindow/components/MapButtons/shared/MapToolButton.tsx b/frontend/src/features/MainWindow/components/MapButtons/shared/MapToolButton.tsx index 1386be1fd8..4691e7212e 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/shared/MapToolButton.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/shared/MapToolButton.tsx @@ -11,8 +11,8 @@ type MapToolButtonProps = { isLeftButton?: boolean } & HTMLProps export function MapToolButton({ children, isActive, isLeftButton = false, ...props }: MapToolButtonProps) { - const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const isRightMenuShrinked = !rightMenuIsOpen && !isLeftButton return ( diff --git a/frontend/src/features/MainWindow/components/MapButtons/shared/RightMenuOnHoverArea.tsx b/frontend/src/features/MainWindow/components/MapButtons/shared/RightMenuOnHoverArea.tsx index 632f3ee476..a41f7db02a 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/shared/RightMenuOnHoverArea.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/shared/RightMenuOnHoverArea.tsx @@ -4,12 +4,12 @@ import { useMainAppSelector } from '@hooks/useMainAppSelector' import { useEffect, useRef } from 'react' import styled from 'styled-components' -import { contractRightMenu, expandRightMenu } from '../../../../../domain/shared_slices/Global' +import { contractRightMenu, expandRightMenu } from '../../../slice' export function RightMenuOnHoverArea() { const dispatch = useMainAppDispatch() const selectedVessel = useMainAppSelector(state => state.vessel.selectedVessel) - const rightMapBoxOpened = useMainAppSelector(state => state.global.rightMapBoxOpened) + const rightMapBoxOpened = useMainAppSelector(state => state.mainWindow.rightMapBoxOpened) const areaRef = useRef(null) const clickedOutsideComponent = useClickOutsideWhenOpened(areaRef, !!selectedVessel) diff --git a/frontend/src/features/MainWindow/index.tsx b/frontend/src/features/MainWindow/index.tsx index 13948ca319..6b17df3536 100644 --- a/frontend/src/features/MainWindow/index.tsx +++ b/frontend/src/features/MainWindow/index.tsx @@ -1,8 +1,11 @@ +import { MissionMenuDialog } from '@features/Mission/components/MissionMenuDialog' +import { MapBox } from 'domain/entities/map/constants' import { useCallback } from 'react' import { useBeforeUnload } from 'react-router-dom' import styled from 'styled-components' import { LegacyRsuiteComponentsWrapper } from 'ui/LegacyRsuiteComponentsWrapper' +import { LeftMenu } from './components/LeftMenu' import { MapButtons } from './components/MapButtons' import { APIWorker } from '../../api/APIWorker' import { Notifier } from '../../components/Notifier' @@ -35,6 +38,7 @@ export function MainWindow() { const isVesselSearchDisplayed = useMainAppSelector(state => state.displayedComponent.isVesselSearchDisplayed) const isVesselSidebarOpen = useMainAppSelector(state => state.vessel.vesselSidebarIsOpen) const isDraftDirty = useMainAppSelector(state => state.missionForm.isDraftDirty) + const leftDialog = useMainAppSelector(state => state.mainWindow.leftDialog) const status = useMainAppSelector(state => state.sideWindow.status) const warnOnUnload = useCallback( @@ -53,14 +57,16 @@ export function MainWindow() { useBeforeUnload(warnOnUnload) return ( - <> + - + + - + + {isVesselSearchDisplayed && } @@ -80,13 +86,24 @@ export function MainWindow() { {status !== SideWindowStatus.CLOSED && } {isDrawLayerModalDisplayed && } - - + + + {leftDialog?.key === MapBox.MISSIONS && } + ) } const Wrapper = styled.div` + display: flex; + flex-direction: column; + height: 100vh; + width: 100vw; +` + +const MapWrapper = styled.div` + box-sizing: border-box; + flex-grow: 1; font-size: 13px; overflow: hidden; - width: 100vw; + position: relative; ` diff --git a/frontend/src/domain/shared_slices/Global.ts b/frontend/src/features/MainWindow/slice.ts similarity index 78% rename from frontend/src/domain/shared_slices/Global.ts rename to frontend/src/features/MainWindow/slice.ts index 727b616303..61480a19ec 100644 --- a/frontend/src/domain/shared_slices/Global.ts +++ b/frontend/src/features/MainWindow/slice.ts @@ -1,17 +1,17 @@ import { createSlice } from '@reduxjs/toolkit' +import { UserType } from '../../domain/entities/beaconMalfunction/constants' +import { getOnlyVesselIdentityProperties, vesselsAreEquals } from '../../domain/entities/vessel/vessel' import { getLocalStorageState } from '../../utils' -import { UserType } from '../entities/beaconMalfunction/constants' -import { getOnlyVesselIdentityProperties, vesselsAreEquals } from '../entities/vessel/vessel' -import type { MapBox } from '../entities/map/constants' +import type { MapBox } from '../../domain/entities/map/constants' import type { PayloadAction } from '@reduxjs/toolkit' +import type { VesselIdentity } from 'domain/entities/vessel/types' const userTypeLocalStorageKey = 'userType' const lastSearchedVesselsLocalStorageKey = 'lastSearchedVessels' -// TODO Properly type this redux state. -export type GlobalState = { +export type MainWindowState = { blockVesselsUpdate: boolean error: any // TODO Rename this prop. @@ -19,6 +19,12 @@ export type GlobalState = { isBackoffice: boolean isUpdatingVessels: boolean lastSearchedVessels: any[] + leftDialog: + | { + key: MapBox + topPosition: number + } + | undefined leftMapBoxOpened: MapBox | undefined // TODO Rename this prop. // TODO Investigate that. Should be a defined boolean. @@ -28,13 +34,14 @@ export type GlobalState = { userType: string vesselListModalIsOpen: boolean } -const INITIAL_STATE: GlobalState = { +const INITIAL_STATE: MainWindowState = { blockVesselsUpdate: false, error: null, healthcheckTextWarning: [], isBackoffice: false, isUpdatingVessels: false, lastSearchedVessels: getLocalStorageState([], lastSearchedVesselsLocalStorageKey), + leftDialog: undefined, leftMapBoxOpened: undefined, previewFilteredVesselsMode: undefined, rightMapBoxOpened: undefined, @@ -43,20 +50,16 @@ const INITIAL_STATE: GlobalState = { vesselListModalIsOpen: false } -// TODO Properly type this redux reducers. -export const globalSlice = createSlice({ +export const mainWindowSlice = createSlice({ initialState: INITIAL_STATE, name: 'global', reducers: { /** * Adds a vessel to the last searched vessels list showed below * the vessel search input on click - * @function addLastSearchedVessel - * @memberOf GlobalReducer - * @param {Object=} state - * @param {{payload: VesselIdentity}} action - The last searched vessel */ - addSearchedVessel(state, action) { + addSearchedVessel(state, action: PayloadAction) { + // TODO Is it useful since it seems we already receive a `VesselIdentity` (if typings are right)? const vesselIdentityToAdd = getOnlyVesselIdentityProperties(action.payload) // Remove vessel if already in the list @@ -75,6 +78,13 @@ export const globalSlice = createSlice({ window.localStorage.setItem(lastSearchedVesselsLocalStorageKey, JSON.stringify(state.lastSearchedVessels)) }, + /** + * Close the left dialog. + */ + closeLeftDialog(state) { + state.leftDialog = undefined + }, + closeVesselListModal(state) { state.vesselListModalIsOpen = false }, @@ -103,10 +113,8 @@ export const globalSlice = createSlice({ /** * Block or not the vessel update cron - The vessel update is blocked when the * vessel list table is opened or when vessels filters are previewed - * @param {Object=} state - * @param {{payload: boolean}} action - blocked when true */ - setBlockVesselsUpdate(state, action) { + setBlockVesselsUpdate(state, action: PayloadAction) { state.blockVesselsUpdate = action.payload }, @@ -161,20 +169,29 @@ export const globalSlice = createSlice({ /** * Set the user type as OPS or SIP - * @function setUserType - * @memberOf GlobalReducer - * @param {Object=} state - * @param {{payload: string}} action - The user type */ - setUserType(state, action) { + setUserType(state, action: PayloadAction) { state.userType = action.payload window.localStorage.setItem(userTypeLocalStorageKey, JSON.stringify(state.userType)) + }, + + /** + * Toggle the left dialog. + */ + toggleLeftDialog( + state, + action: PayloadAction<{ + key: MapBox + topPosition: number + }> + ) { + state.leftDialog = action.payload.key === state.leftDialog?.key ? undefined : action.payload } } }) -export const globalActions = globalSlice.actions -export const globalSliceReducer = globalSlice.reducer +export const mainWindowActions = mainWindowSlice.actions +export const mainWindowSliceReducer = mainWindowSlice.reducer export const { addSearchedVessel, @@ -193,4 +210,4 @@ export const { setPreviewFilteredVesselsMode, setRightMapBoxOpened, setUserType -} = globalSlice.actions +} = mainWindowSlice.actions diff --git a/frontend/src/features/Measurement/components/MeasurementMapButton/CustomCircleRange.tsx b/frontend/src/features/Measurement/components/MeasurementMapButton/CustomCircleRange.tsx index f122132c06..cd1c414674 100644 --- a/frontend/src/features/Measurement/components/MeasurementMapButton/CustomCircleRange.tsx +++ b/frontend/src/features/Measurement/components/MeasurementMapButton/CustomCircleRange.tsx @@ -1,6 +1,7 @@ +import { setRightMapBoxOpened } from '@features/MainWindow/slice' import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { useMainAppSelector } from '@hooks/useMainAppSelector' -import { CoordinatesInput } from '@mtes-mct/monitor-ui' +import { CoordinatesInput, type Coordinates } from '@mtes-mct/monitor-ui' import { transform } from 'ol/proj' import { useCallback, useMemo } from 'react' import styled from 'styled-components' @@ -12,7 +13,6 @@ import { OPENLAYERS_PROJECTION, WSG84_PROJECTION } from '../../../../domain/entities/map/constants' -import { setRightMapBoxOpened } from '../../../../domain/shared_slices/Global' import { MapToolBox } from '../../../MainWindow/components/MapButtons/shared/MapToolBox' import { resetCircleMeasurementInDrawing, @@ -21,8 +21,6 @@ import { setMeasurementTypeToAdd } from '../../slice' -import type { Coordinates } from '@mtes-mct/monitor-ui' - export function CustomCircleRange() { const dispatch = useMainAppDispatch() const coordinatesFormat = useMainAppSelector(state => state.map.coordinatesFormat) diff --git a/frontend/src/features/Measurement/components/MeasurementMapButton/index.tsx b/frontend/src/features/Measurement/components/MeasurementMapButton/index.tsx index 52ca8a2a9c..c84eab0e1f 100644 --- a/frontend/src/features/Measurement/components/MeasurementMapButton/index.tsx +++ b/frontend/src/features/Measurement/components/MeasurementMapButton/index.tsx @@ -1,3 +1,4 @@ +import { setRightMapBoxOpened } from '@features/MainWindow/slice' import { useClickOutsideWhenOpenedAndExecute } from '@hooks/useClickOutsideWhenOpenedAndExecute' import { useEscapeFromKeyboardAndExecute } from '@hooks/useEscapeFromKeyboardAndExecute' import { useMainAppDispatch } from '@hooks/useMainAppDispatch' @@ -7,7 +8,6 @@ import styled from 'styled-components' import { CustomCircleRange } from './CustomCircleRange' import { MapBox, MeasurementType } from '../../../../domain/entities/map/constants' -import { setRightMapBoxOpened } from '../../../../domain/shared_slices/Global' import { MapComponent } from '../../../commonStyles/MapComponent' import MultiLineSVG from '../../../icons/standardized/Measure_broken_line.svg?react' import CircleRangeSVG from '../../../icons/standardized/Measure_circle.svg?react' @@ -18,8 +18,8 @@ import { setMeasurementTypeToAdd } from '../../slice' export function MeasurementMapButton() { const dispatch = useMainAppDispatch() const measurementTypeToAdd = useMainAppSelector(state => state.measurement.measurementTypeToAdd) - const rightMapBoxOpened = useMainAppSelector(state => state.global.rightMapBoxOpened) - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const rightMapBoxOpened = useMainAppSelector(state => state.mainWindow.rightMapBoxOpened) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const isRightMenuShrinked = !rightMenuIsOpen const isOpen = useMemo(() => rightMapBoxOpened === MapBox.MEASUREMENT_MENU, [rightMapBoxOpened]) diff --git a/frontend/src/features/Mission/components/MissionMenuDialog.tsx b/frontend/src/features/Mission/components/MissionMenuDialog.tsx new file mode 100644 index 0000000000..fd563b083c --- /dev/null +++ b/frontend/src/features/Mission/components/MissionMenuDialog.tsx @@ -0,0 +1,129 @@ +import { addMission } from '@features/Mission/useCases/addMission' +import { openSideWindowPath } from '@features/SideWindow/useCases/openSideWindowPath' +import { useMainAppDispatch } from '@hooks/useMainAppDispatch' +import { useMainAppSelector } from '@hooks/useMainAppSelector' +import { Accent, Button, Icon, IconButton, Size } from '@mtes-mct/monitor-ui' +import { assertNotNullish } from '@utils/assertNotNullish' +import { useCallback } from 'react' +import styled from 'styled-components' + +import { SideWindowMenuKey, SideWindowStatus } from '../../../domain/entities/sideWindow/constants' +import { setDisplayedComponents } from '../../../domain/shared_slices/DisplayedComponent' +import { sideWindowActions } from '../../../domain/shared_slices/SideWindow' +import { mainWindowActions } from '../../MainWindow/slice' + +export function MissionMenuDialog() { + const dispatch = useMainAppDispatch() + const sideWindow = useMainAppSelector(state => state.sideWindow) + const isMissionsLayerDisplayed = useMainAppSelector(state => state.displayedComponent.isMissionsLayerDisplayed) + const leftDialog = useMainAppSelector(state => state.mainWindow.leftDialog) + assertNotNullish(leftDialog) + + const isActive = + sideWindow.status !== SideWindowStatus.CLOSED && sideWindow.selectedPath.menu === SideWindowMenuKey.MISSION_LIST + + const toggleMissionsWindow = useCallback(() => { + if (isActive) { + dispatch(sideWindowActions.close()) + + return + } + + dispatch(openSideWindowPath({ menu: SideWindowMenuKey.MISSION_LIST })) + }, [dispatch, isActive]) + + const openNewMission = () => { + dispatch(addMission()) + } + + const close = () => { + dispatch(mainWindowActions.closeLeftDialog()) + } + + const toggleMissionsLayer = () => { + dispatch(setDisplayedComponents({ isMissionsLayerDisplayed: !isMissionsLayerDisplayed })) + } + + return ( + + + + Missions et contrôles + + + +
+ + Ouvrir une nouvelle mission + +
+
+ + Voir la vue détaillée des missions + +
+
+
+ ) +} + +const Wrapper = styled.div` + box-sizing: border-box; + background-color: ${p => p.theme.color.white}; + left: 160px; + position: absolute; + transition: all 0.2s; + width: 320px; + + * { + box-sizing: border-box; + } +` + +const MissionsMenuHeader = styled.div` + height: 40px; + background-color: ${p => p.theme.color.charcoal}; + display: flex; + justify-content: space-between; + padding-right: 5px; + padding-left: 5px; + align-items: center; +` + +const Title = styled.span` + font-size: 16px; + line-height: 22px; + color: ${p => p.theme.color.white}; +` + +const MissionsMenuBody = styled.div`` +const Section = styled.div` + padding: 12px; + &:not(:last-child) { + border-bottom: 1px solid ${p => p.theme.color.gainsboro}; + } +` + +const ToggleMissionsButton = styled(IconButton)` + background: ${p => p.theme.color.white}; + + :hover { + background: ${p => p.theme.color.white}; + } + :focus { + background: ${p => p.theme.color.white}; + } +` +const ToggleMissionMenuButton = styled(IconButton)` + color: white; +` +const BlockIconButton = styled(Button)` + width: 100%; +` diff --git a/frontend/src/features/Regulation/components/RegulationSearch/constants.ts b/frontend/src/features/Regulation/components/RegulationSearch/constants.ts index e623f33f6f..fc95e2caf6 100644 --- a/frontend/src/features/Regulation/components/RegulationSearch/constants.ts +++ b/frontend/src/features/Regulation/components/RegulationSearch/constants.ts @@ -1,7 +1,7 @@ import type { RegulatoryZone } from '../../types' import type { IFuseOptions } from 'fuse.js' -export const REGULATION_SEARCH_OPTIONS: IFuseOptions = { +export const REGULATION_SEARCH_OPTIONS: IFuseOptions = { ignoreLocation: true, includeScore: false, keys: [ diff --git a/frontend/src/features/Regulation/useCases/getAllRegulatoryLayersByRegTerritory.ts b/frontend/src/features/Regulation/useCases/getAllRegulatoryLayersByRegTerritory.ts index 0c5229774b..b55bd9f95c 100644 --- a/frontend/src/features/Regulation/useCases/getAllRegulatoryLayersByRegTerritory.ts +++ b/frontend/src/features/Regulation/useCases/getAllRegulatoryLayersByRegTerritory.ts @@ -1,6 +1,6 @@ import { getAllRegulatoryLayersFromAPI } from '../../../api/geoserver' -import { setError } from '../../../domain/shared_slices/Global' import { MonitorFishWorker } from '../../../workers/MonitorFishWorker' +import { setError } from '../../MainWindow/slice' import { setLayersTopicsByRegTerritory, setRegulatoryLayerLawTypes } from '../slice' export const getAllRegulatoryLayersByRegTerritory = () => async (dispatch, getState) => { @@ -13,7 +13,7 @@ export const getAllRegulatoryLayersByRegTerritory = () => async (dispatch, getSt } try { - const features = await getAllRegulatoryLayersFromAPI(getState().global.isBackoffice) + const features = await getAllRegulatoryLayersFromAPI(getState().mainWindow.isBackoffice) const { layersTopicsByRegulatoryTerritory } = await monitorFishWorker.convertGeoJSONFeaturesToStructuredRegulatoryObject(features, speciesByCode) diff --git a/frontend/src/features/Regulation/useCases/getGeometryWithoutRegulationReference.ts b/frontend/src/features/Regulation/useCases/getGeometryWithoutRegulationReference.ts index 1f3b2ba2c2..42d2e49a23 100644 --- a/frontend/src/features/Regulation/useCases/getGeometryWithoutRegulationReference.ts +++ b/frontend/src/features/Regulation/useCases/getGeometryWithoutRegulationReference.ts @@ -1,6 +1,6 @@ import { getAllGeometryWithoutProperty } from '../../../api/geoserver' -import { setError } from '../../../domain/shared_slices/Global' import { MonitorFishWorker } from '../../../workers/MonitorFishWorker' +import { setError } from '../../MainWindow/slice' import type { GeoJSON } from '../../../domain/types/GeoJSON' @@ -10,7 +10,7 @@ export const getGeometryWithoutRegulationReference = const monitorFishWorker = await MonitorFishWorker try { - const features = await getAllGeometryWithoutProperty(getState().global.isBackoffice) + const features = await getAllGeometryWithoutProperty(getState().mainWindow.isBackoffice) return await monitorFishWorker.getIdToGeometryObject(features) } catch (e) { diff --git a/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts b/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts index ed5e541322..61e52c9849 100644 --- a/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts +++ b/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts @@ -6,6 +6,7 @@ import { MonitorFishWorker } from '../../../workers/MonitorFishWorker' import { REGULATION_SEARCH_OPTIONS } from '../components/RegulationSearch/constants' import type { RegulatoryLawTypes, RegulatoryZone } from '../types' +import type { MainAppThunk } from '@store' export const MINIMUM_SEARCH_CHARACTERS_NUMBER = 2 @@ -13,9 +14,10 @@ export const MINIMUM_SEARCH_CHARACTERS_NUMBER = 2 * Search for regulatory zones in the regulatory referential, by zone (geometry) and by the input filters */ export const searchRegulatoryLayers = - (searchQuery: string | undefined) => + (searchQuery: string | undefined): MainAppThunk => async (_, getState): Promise => { const monitorFishWorker = await MonitorFishWorker + const { regulatoryZones } = getState().regulatory const { zoneSelected } = getState().regulatoryLayerSearch const { speciesByCode } = getState().species @@ -24,7 +26,7 @@ export const searchRegulatoryLayers = const extent = getExtentFromGeoJSON(zoneSelected.feature) if (extent?.length === 4) { - return getRegulatoryZonesInExtentFromAPI(extent, getState().global.isBackoffice) + return getRegulatoryZonesInExtentFromAPI(extent, getState().mainWindow.isBackoffice) .then(features => monitorFishWorker.mapGeoserverToRegulatoryZones(features, speciesByCode)) .then(filteredRegulatoryZones => { if (!searchQuery || searchQuery.length < MINIMUM_SEARCH_CHARACTERS_NUMBER) { diff --git a/frontend/src/features/Regulation/useCases/showRegulationToEdit.js b/frontend/src/features/Regulation/useCases/showRegulationToEdit.js index a497bb7578..c36d6bfe9f 100644 --- a/frontend/src/features/Regulation/useCases/showRegulationToEdit.js +++ b/frontend/src/features/Regulation/useCases/showRegulationToEdit.js @@ -1,6 +1,7 @@ +import { setError } from '@features/MainWindow/slice' + import { getRegulatoryZoneFromAPI, REGULATORY_ZONE_METADATA_ERROR_MESSAGE } from '../../../api/geoserver' import { LayerProperties } from '../../../domain/entities/layers/constants' -import { setError } from '../../../domain/shared_slices/Global' import { STATUS } from '../../BackOffice/constants' import { setProcessingRegulation, setSelectedRegulatoryZoneId, setStatus } from '../../BackOffice/slice' import { mapToRegulatoryZone, DEFAULT_REGULATORY_TEXT } from '../utils' @@ -9,7 +10,7 @@ const showRegulationToEdit = regulatoryZone => async (dispatch, getState) => { const { speciesByCode } = getState().species dispatch(setStatus(STATUS.LOADING)) - return getRegulatoryZoneFromAPI(LayerProperties.REGULATORY.code, regulatoryZone, getState().global.isBackoffice) + return getRegulatoryZoneFromAPI(LayerProperties.REGULATORY.code, regulatoryZone, getState().mainWindow.isBackoffice) .then(feature => { const regulatoryZoneMetadata = mapToRegulatoryZone(feature, speciesByCode) diff --git a/frontend/src/features/Regulation/useCases/showRegulatoryZone.js b/frontend/src/features/Regulation/useCases/showRegulatoryZone.js index 151034faac..269a46c519 100644 --- a/frontend/src/features/Regulation/useCases/showRegulatoryZone.js +++ b/frontend/src/features/Regulation/useCases/showRegulatoryZone.js @@ -67,7 +67,7 @@ const getRegulatoryVectorSource = (dispatch, getState) => regulatoryZoneProperti getRegulatoryZoneFromAPI( LayerProperties.REGULATORY.code, regulatoryZoneProperties, - getState().global.isBackoffice + getState().mainWindow.isBackoffice ) .then(regulatoryZone => { if (!regulatoryZone.geometry) { diff --git a/frontend/src/features/Regulation/useCases/showRegulatoryZoneMetadata.ts b/frontend/src/features/Regulation/useCases/showRegulatoryZoneMetadata.ts index f2987bd44d..0383fa64f1 100644 --- a/frontend/src/features/Regulation/useCases/showRegulatoryZoneMetadata.ts +++ b/frontend/src/features/Regulation/useCases/showRegulatoryZoneMetadata.ts @@ -1,5 +1,5 @@ import { getRegulatoryFeatureMetadataFromAPI } from '../../../api/geoserver' -import { setError } from '../../../domain/shared_slices/Global' +import { setError } from '../../MainWindow/slice' import { closeRegulatoryZoneMetadataPanel, resetLoadingRegulatoryZoneMetadata, @@ -19,7 +19,7 @@ export const showRegulatoryZoneMetadata = dispatch(setLoadingRegulatoryZoneMetadata()) const { speciesByCode } = getState().species - getRegulatoryFeatureMetadataFromAPI(partialRegulatoryZone, getState().global.isBackoffice) + getRegulatoryFeatureMetadataFromAPI(partialRegulatoryZone, getState().mainWindow.isBackoffice) .then(feature => { const parsedRegulatoryZone = mapToRegulatoryZone(feature, speciesByCode) dispatch(setRegulatoryZoneMetadata(parsedRegulatoryZone)) diff --git a/frontend/src/features/Regulation/useCases/updateRegulation.js b/frontend/src/features/Regulation/useCases/updateRegulation.js index 1fd153a264..4ef253a43c 100644 --- a/frontend/src/features/Regulation/useCases/updateRegulation.js +++ b/frontend/src/features/Regulation/useCases/updateRegulation.js @@ -1,5 +1,6 @@ +import { setError } from '@features/MainWindow/slice' + import { sendRegulationTransaction } from '../../../api/geoserver' -import { setError } from '../../../domain/shared_slices/Global' import { setProcessingRegulationSaved, setProcessingRegulationDeleted } from '../../BackOffice/slice' import { REGULATION_ACTION_TYPE } from '../utils' diff --git a/frontend/src/features/Regulation/useCases/updateTopicForAllZones.js b/frontend/src/features/Regulation/useCases/updateTopicForAllZones.js index 9f68a703fd..0ba65471bc 100644 --- a/frontend/src/features/Regulation/useCases/updateTopicForAllZones.js +++ b/frontend/src/features/Regulation/useCases/updateTopicForAllZones.js @@ -1,7 +1,7 @@ import { Feature } from 'ol' import { sendRegulationTransaction } from '../../../api/geoserver' -import { setError } from '../../../domain/shared_slices/Global' +import { setError } from '../../MainWindow/slice' import { setLayersTopicsByRegTerritory, setRegulatoryLayerLawTypes } from '../slice' import { getRegulatoryFeatureId, mapToRegulatoryFeatureObject, REGULATION_ACTION_TYPE } from '../utils' diff --git a/frontend/src/features/Reporting/useCases/addReporting.ts b/frontend/src/features/Reporting/useCases/addReporting.ts index 65049c7a9c..b94b46f8cc 100644 --- a/frontend/src/features/Reporting/useCases/addReporting.ts +++ b/frontend/src/features/Reporting/useCases/addReporting.ts @@ -1,6 +1,7 @@ import { addReportingFromAPI } from '@api/reporting' import { getVesselReportings } from '@features/Reporting/useCases/getVesselReportings' import { DisplayedErrorKey } from '@libs/DisplayedError/constants' +import { logSoftError } from '@mtes-mct/monitor-ui' import { Vessel } from '../../../domain/entities/vessel/vessel' import { addVesselReporting } from '../../../domain/shared_slices/Vessel' @@ -14,6 +15,15 @@ export const addReporting = (newReporting: ReportingCreation): MainAppThunk => async (dispatch, getState) => { const { selectedVesselIdentity } = getState().vessel + // TODO Can this case happen? Is it the right way to handle it? + if (!selectedVesselIdentity) { + logSoftError({ + message: '`selectedVesselIdentity` is null.', + userMessage: 'Aucun navire sélectionné pour ajouter un signalement.' + }) + + return + } try { const reporting = await addReportingFromAPI(newReporting) diff --git a/frontend/src/features/Reporting/useCases/deleteReporting.ts b/frontend/src/features/Reporting/useCases/deleteReporting.ts index 3a9f62f2ee..756406283e 100644 --- a/frontend/src/features/Reporting/useCases/deleteReporting.ts +++ b/frontend/src/features/Reporting/useCases/deleteReporting.ts @@ -2,6 +2,7 @@ import { deleteReportingFromAPI } from '@api/reporting' import { ReportingType } from '@features/Reporting/types' import { getVesselReportings } from '@features/Reporting/useCases/getVesselReportings' import { DisplayedErrorKey } from '@libs/DisplayedError/constants' +import { logSoftError } from '@mtes-mct/monitor-ui' import { Vessel } from '../../../domain/entities/vessel/vessel' import { removeVesselReporting } from '../../../domain/shared_slices/Vessel' @@ -14,6 +15,15 @@ export const deleteReporting = (id: number, reportingType: ReportingType): MainAppThunk => async (dispatch, getState) => { const { selectedVesselIdentity } = getState().vessel + // TODO Can this case happen? Is it the right way to handle it? + if (!selectedVesselIdentity) { + logSoftError({ + message: '`selectedVesselIdentity` is null.', + userMessage: 'Aucun navire sélectionné pour supprimer un signalement.' + }) + + return + } try { await deleteReportingFromAPI(id) diff --git a/frontend/src/features/Reporting/useCases/getAllCurrentReportings.ts b/frontend/src/features/Reporting/useCases/getAllCurrentReportings.ts index 8ea1fa648f..04d7f1b4e7 100644 --- a/frontend/src/features/Reporting/useCases/getAllCurrentReportings.ts +++ b/frontend/src/features/Reporting/useCases/getAllCurrentReportings.ts @@ -1,6 +1,6 @@ import { getAllCurrentReportingsFromAPI } from '@api/reporting' +import { removeError, setError } from '@features/MainWindow/slice' -import { removeError, setError } from '../../../domain/shared_slices/Global' import { setCurrentReportings } from '../slice' export const getAllCurrentReportings = () => dispatch => diff --git a/frontend/src/features/Reporting/useCases/getVesselReportings.ts b/frontend/src/features/Reporting/useCases/getVesselReportings.ts index b6656188f5..80e1f64809 100644 --- a/frontend/src/features/Reporting/useCases/getVesselReportings.ts +++ b/frontend/src/features/Reporting/useCases/getVesselReportings.ts @@ -1,8 +1,8 @@ import { getVesselReportingsFromAPI } from '@api/vessel' +import { removeError } from '@features/MainWindow/slice' import { DisplayedErrorKey } from '@libs/DisplayedError/constants' import { displayedErrorActions } from '../../../domain/shared_slices/DisplayedError' -import { removeError } from '../../../domain/shared_slices/Global' import { displayOrLogError } from '../../../domain/use_cases/error/displayOrLogError' import { loadReporting, diff --git a/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/SilenceAlertMenu.tsx b/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/SilenceAlertMenu.tsx index 7fa34d6581..6f98557065 100644 --- a/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/SilenceAlertMenu.tsx +++ b/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/SilenceAlertMenu.tsx @@ -34,7 +34,7 @@ export function SilenceAlertMenu({ silenceAlert }: SilenceAlertMenuProps) { const silencedAlertRef = useRef() as MutableRefObject - const clickedOutside = useClickOutsideWhenOpenedWithinRef(silencedAlertRef, showSilencedAlertForIndex, baseRef) + const clickedOutside = useClickOutsideWhenOpenedWithinRef(silencedAlertRef, showSilencedAlertForIndex > 0, baseRef) const { forceUpdate } = useForceUpdate() useEffect(() => { diff --git a/frontend/src/features/SideWindow/BeaconMalfunctionBoard/BeaconMalfunctionDetailsFollowUp.tsx b/frontend/src/features/SideWindow/BeaconMalfunctionBoard/BeaconMalfunctionDetailsFollowUp.tsx index a6acb22e78..ff185f7299 100644 --- a/frontend/src/features/SideWindow/BeaconMalfunctionBoard/BeaconMalfunctionDetailsFollowUp.tsx +++ b/frontend/src/features/SideWindow/BeaconMalfunctionBoard/BeaconMalfunctionDetailsFollowUp.tsx @@ -8,7 +8,6 @@ import { BeaconMalfunctionDetailsFollowUpRow } from './BeaconMalfunctionDetailsF import { BeaconMalfunctionDetailsType, getContent } from './beaconMalfunctions' import { COLORS } from '../../../constants/constants' import { UserType, VESSEL_STATUS } from '../../../domain/entities/beaconMalfunction/constants' -import { setUserType } from '../../../domain/shared_slices/Global' import saveBeaconMalfunctionCommentFromKanban from '../../../domain/use_cases/beaconMalfunction/saveBeaconMalfunctionCommentFromKanban' import { useListenForScroll } from '../../../hooks/useListenForScroll' import { useMainAppDispatch } from '../../../hooks/useMainAppDispatch' @@ -16,6 +15,7 @@ import { useMainAppSelector } from '../../../hooks/useMainAppSelector' import { getDate, mergeObjects } from '../../../utils' import { pushToObjectAtIndex } from '../../../utils/pushToObjectAtIndex' import CommentsSVG from '../../icons/Commentaires.svg?react' +import { setUserType } from '../../MainWindow/slice' import type { BeaconMalfunctionFollowUpItem, @@ -26,7 +26,7 @@ import type { CSSProperties } from 'react' export function BeaconMalfunctionDetailsFollowUp({ beaconMalfunctionWithDetails, firstStatus, smallSize }) { const { actions, beaconMalfunction, comments, notifications } = beaconMalfunctionWithDetails const dispatch = useMainAppDispatch() - const userType = useMainAppSelector(state => state.global.userType) + const userType = useMainAppSelector(state => state.mainWindow.userType) const firstVesselStatus = VESSEL_STATUS.find(status => status.value === firstStatus) as BeaconMalfunctionStatusValue const [today, setToday] = useState('') const [yesterday, setYesterday] = useState('') diff --git a/frontend/src/features/SideWindow/BeaconMalfunctionBoard/index.tsx b/frontend/src/features/SideWindow/BeaconMalfunctionBoard/index.tsx index 0c193721b6..400213ebd6 100644 --- a/frontend/src/features/SideWindow/BeaconMalfunctionBoard/index.tsx +++ b/frontend/src/features/SideWindow/BeaconMalfunctionBoard/index.tsx @@ -21,12 +21,12 @@ import { StageColumn } from './StageColumn' import { VesselStatusSelect } from './VesselStatusSelect' import { COLORS } from '../../../constants/constants' import { STAGE_RECORD, VESSEL_STATUS } from '../../../domain/entities/beaconMalfunction/constants' -import { setError } from '../../../domain/shared_slices/Global' import getAllBeaconMalfunctions from '../../../domain/use_cases/beaconMalfunction/getAllBeaconMalfunctions' import updateBeaconMalfunctionFromKanban from '../../../domain/use_cases/beaconMalfunction/updateBeaconMalfunctionFromKanban' import { useMainAppDispatch } from '../../../hooks/useMainAppDispatch' import { useMainAppSelector } from '../../../hooks/useMainAppSelector' import SearchIconSVG from '../../icons/Loupe_dark.svg?react' +import { setError } from '../../MainWindow/slice' import type { BeaconMalfunction, diff --git a/frontend/src/features/Vessel/components/VesselLoader.tsx b/frontend/src/features/Vessel/components/VesselLoader.tsx index df19db20ce..7993a50c21 100644 --- a/frontend/src/features/Vessel/components/VesselLoader.tsx +++ b/frontend/src/features/Vessel/components/VesselLoader.tsx @@ -1,4 +1,7 @@ +import { setError } from '@features/MainWindow/slice' import { useIsInLightMode } from '@hooks/useIsInLightMode' +import { useMainAppDispatch } from '@hooks/useMainAppDispatch' +import { useMainAppSelector } from '@hooks/useMainAppSelector' import { skipToken } from '@reduxjs/toolkit/query' import { useEffect, useState } from 'react' import { FulfillingBouncingCircleSpinner } from 'react-epic-spinners' @@ -6,9 +9,6 @@ import styled from 'styled-components' import { FIVE_MINUTES, TWENTY_MINUTES } from '../../../api/APIWorker' import { COLORS } from '../../../constants/constants' -import { setError } from '../../../domain/shared_slices/Global' -import { useMainAppDispatch } from '../../../hooks/useMainAppDispatch' -import { useMainAppSelector } from '../../../hooks/useMainAppSelector' import { MapComponent } from '../../commonStyles/MapComponent' import VesselSVG from '../../icons/Icone_navire.svg?react' import { useGetVesselsLastPositionsApi } from '../hooks/useGetVesselsLastPositionsApi' @@ -19,7 +19,7 @@ export function VesselLoader() { const isInLightMode = useIsInLightMode() const dispatch = useMainAppDispatch() - const blockVesselsUpdate = useMainAppSelector(state => state.global.blockVesselsUpdate) + const blockVesselsUpdate = useMainAppSelector(state => state.mainWindow.blockVesselsUpdate) const loadingPositions = useMainAppSelector(state => state.vessel.loadingPositions) const vesselSidebarIsOpen = useMainAppSelector(state => state.vessel.vesselSidebarIsOpen) diff --git a/frontend/src/features/Vessel/useCases/applyFilterToVessels.ts b/frontend/src/features/Vessel/useCases/applyFilterToVessels.ts index e3508314c8..245118b8c0 100644 --- a/frontend/src/features/Vessel/useCases/applyFilterToVessels.ts +++ b/frontend/src/features/Vessel/useCases/applyFilterToVessels.ts @@ -1,7 +1,7 @@ -import { setError } from '../../../domain/shared_slices/Global' import { setAllVesselsAsUnfiltered, setFilteredVesselsFeatures } from '../../../domain/shared_slices/Vessel' import { getFilteredVessels } from '../../../domain/use_cases/vessel/getFilteredVessels' import NoVesselsInFilterError from '../../../errors/NoVesselsInFilterError' +import { setError } from '../../MainWindow/slice' export const applyFilterToVessels = () => (dispatch, getState) => { const showedFilter = getState().filter?.filters?.find(filter => filter.showed) diff --git a/frontend/src/features/Vessel/useCases/showVesselsLastPosition.ts b/frontend/src/features/Vessel/useCases/showVesselsLastPosition.ts index 179725f35a..429c5bafd5 100644 --- a/frontend/src/features/Vessel/useCases/showVesselsLastPosition.ts +++ b/frontend/src/features/Vessel/useCases/showVesselsLastPosition.ts @@ -1,7 +1,7 @@ import { applyFilterToVessels } from './applyFilterToVessels' -import { resetIsUpdatingVessels } from '../../../domain/shared_slices/Global' import { setVesselsFromAPI, setVesselsSpeciesAndDistricts } from '../../../domain/shared_slices/Vessel' import getUniqueSpeciesAndDistricts from '../../../domain/use_cases/species/getUniqueSpeciesAndDistricts' +import { resetIsUpdatingVessels } from '../../MainWindow/slice' import type { VesselLastPosition } from '../../../domain/entities/vessel/types' diff --git a/frontend/src/features/VesselList/index.tsx b/frontend/src/features/VesselList/index.tsx index bd7a469470..2bdc777516 100644 --- a/frontend/src/features/VesselList/index.tsx +++ b/frontend/src/features/VesselList/index.tsx @@ -17,7 +17,6 @@ import { InteractionListener, InteractionType } from '../../domain/entities/map/ import { VesselLocation } from '../../domain/entities/vessel/vessel' import { setDisplayedComponents } from '../../domain/shared_slices/DisplayedComponent' import { addFilter } from '../../domain/shared_slices/Filter' -import { setBlockVesselsUpdate, setPreviewFilteredVesselsMode } from '../../domain/shared_slices/Global' import { animateToExtent } from '../../domain/shared_slices/Map' import { setPreviewFilteredVesselsFeatures } from '../../domain/shared_slices/Vessel' import { addVesselListFilterZone } from '../../domain/use_cases/vessel/addVesselListFilterZone' @@ -36,6 +35,7 @@ import { resetInteraction } from '../Draw/slice' import { useGetFleetSegmentsQuery } from '../FleetSegment/apis' import VesselListSVG from '../icons/Icone_liste_navires.svg?react' import PreviewSVG from '../icons/Oeil_apercu_carte.svg?react' +import { setBlockVesselsUpdate, setPreviewFilteredVesselsMode } from '../MainWindow/slice' import { setProcessingRegulationSearchedZoneExtent } from '../Regulation/slice' import type { VesselEnhancedLastPositionWebGLObject } from '../../domain/entities/vessel/types' @@ -64,7 +64,7 @@ type ZoneGroupAndChildren = { export function VesselList({ namespace }) { const dispatch = useMainAppDispatch() - const { previewFilteredVesselsMode, rightMenuIsOpen } = useMainAppSelector(state => state.global) + const { previewFilteredVesselsMode, rightMenuIsOpen } = useMainAppSelector(state => state.mainWindow) const isVesselListModalDisplayed = useMainAppSelector(state => state.displayedComponent.isVesselListModalDisplayed) const { drawedGeometry } = useListenForDrawedGeometry(InteractionListener.VESSELS_LIST) const { @@ -424,7 +424,7 @@ export function VesselList({ namespace }) { setDistrictsFiltered }} fleetSegments={{ - fleetSegments: getFleetSegmentsQuery.data || [], + fleetSegments: getFleetSegmentsQuery.data ?? [], fleetSegmentsFiltered, setFleetSegmentsFiltered }} diff --git a/frontend/src/features/VesselSearch/VesselSearchResult.tsx b/frontend/src/features/VesselSearch/VesselSearchResult.tsx index da05ecba0b..1973ae4edb 100644 --- a/frontend/src/features/VesselSearch/VesselSearchResult.tsx +++ b/frontend/src/features/VesselSearch/VesselSearchResult.tsx @@ -6,7 +6,7 @@ import { VesselSearchResultItem } from './VesselSearchResultItem' import { getVesselCompositeIdentifier } from '../../domain/entities/vessel/vessel' export function VesselSearchResult({ foundVessels, searchQuery, selectVessel, showLastSearchedVessels }) { - const lastSearchedVessels = useMainAppSelector(state => state.global.lastSearchedVessels) + const lastSearchedVessels = useMainAppSelector(state => state.mainWindow.lastSearchedVessels) const baseUrl = useMemo(() => window.location.origin, []) return ( diff --git a/frontend/src/features/VesselSearch/index.tsx b/frontend/src/features/VesselSearch/index.tsx index 96a235bc38..76c8aac45b 100644 --- a/frontend/src/features/VesselSearch/index.tsx +++ b/frontend/src/features/VesselSearch/index.tsx @@ -20,6 +20,7 @@ import type { ChangeEvent, InputHTMLAttributes, MutableRefObject } from 'react' import type { Promisable } from 'type-fest' type VesselSearchProps = Omit, 'defaultValue' | 'onChange'> & { + // TODO Should be `MutableRefObject | undefined`. baseRef?: MutableRefObject | undefined defaultValue?: VesselIdentity | undefined extendedWidth?: number | undefined @@ -53,7 +54,7 @@ export function VesselSearch({ const selectedVesselIdentity = useMainAppSelector(state => state.vessel.selectedVesselIdentity) const vessels = useMainAppSelector(state => state.vessel.vessels) const searchQueryRef = useRef('') - const wrapperRef = useRef(null) + const wrapperRef = useRef(null) const [selectedVessel, setSelectedVessel] = useState(undefined) const [foundVessels, setFoundVessels] = useState([]) diff --git a/frontend/src/features/VesselSidebar/Body.tsx b/frontend/src/features/VesselSidebar/Body.tsx index 430b551c31..2ffd572965 100644 --- a/frontend/src/features/VesselSidebar/Body.tsx +++ b/frontend/src/features/VesselSidebar/Body.tsx @@ -19,7 +19,7 @@ import { VesselReportings } from '../Reporting/components/VesselReportings' export function Body() { const isSuperUser = useIsSuperUser() const dispatch = useMainAppDispatch() - const healthcheckTextWarning = useMainAppSelector(state => state.global.healthcheckTextWarning) + const healthcheckTextWarning = useMainAppSelector(state => state.mainWindow.healthcheckTextWarning) const vesselSidebarError = useMainAppSelector(state => state.displayedError.vesselSidebarError) const selectedVessel = useMainAppSelector(state => state.vessel.selectedVessel) const vesselSidebarTab = useMainAppSelector(state => state.vessel.vesselSidebarTab) diff --git a/frontend/src/features/VesselSidebar/VesselSidebarHeader/VesselName.tsx b/frontend/src/features/VesselSidebar/VesselSidebarHeader/VesselName.tsx index 112d00fb8c..af013bb8ee 100644 --- a/frontend/src/features/VesselSidebar/VesselSidebarHeader/VesselName.tsx +++ b/frontend/src/features/VesselSidebar/VesselSidebarHeader/VesselName.tsx @@ -1,3 +1,4 @@ +import { logSoftError } from '@mtes-mct/monitor-ui' import countries from 'i18n-iso-countries' import { useCallback, useMemo } from 'react' import styled from 'styled-components' @@ -29,6 +30,15 @@ export function VesselName({ focusOnVesselSearchInput }) { const addOrRemoveToFavorites = useCallback( e => { e.stopPropagation() + // TODO Can this case happen? Is it the right way to handle it? + if (!selectedVesselIdentity) { + logSoftError({ + message: '`selectedVesselIdentity` is null.', + userMessage: 'Aucun navire sélectionné à ajouter ou supprimer des favoris.' + }) + + return + } if (isFavorite) { dispatch(removeVesselFromFavorites(getVesselCompositeIdentifier(selectedVesselIdentity))) diff --git a/frontend/src/features/VesselSidebar/VesselSidebarHeader/index.tsx b/frontend/src/features/VesselSidebar/VesselSidebarHeader/index.tsx index 86382c3025..95036140b3 100644 --- a/frontend/src/features/VesselSidebar/VesselSidebarHeader/index.tsx +++ b/frontend/src/features/VesselSidebar/VesselSidebarHeader/index.tsx @@ -5,12 +5,12 @@ import styled from 'styled-components' import { VesselName } from './VesselName' import { vesselsAreEquals } from '../../../domain/entities/vessel/vessel' -import { expandRightMenu } from '../../../domain/shared_slices/Global' import { setIsFocusedOnVesselSearch } from '../../../domain/shared_slices/Vessel' import { showVessel } from '../../../domain/use_cases/vessel/showVessel' import { MapComponent } from '../../commonStyles/MapComponent' import SearchIconSVG from '../../icons/Loupe.svg?react' import { MapButton } from '../../MainWindow/components/MapButtons/MapButton' +import { expandRightMenu } from '../../MainWindow/slice' import { VesselSearch } from '../../VesselSearch' import type { VesselIdentity } from '../../../domain/entities/vessel/types' @@ -22,8 +22,8 @@ export function VesselSidebarHeader() { state => state.vessel ) - const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const isVesselNameShown = !isFocusedOnVesselSearch && selectedVesselIdentity const isRightMenuShrinked = vesselSidebarIsOpen && !rightMenuIsOpen @@ -113,7 +113,7 @@ const SearchButton = styled(MapButton)<{ width: 40px; height: 40px; right: 10px; - top: 10px; + top: 12px; z-index: 99; cursor: pointer; border-radius: 2px; diff --git a/frontend/src/features/VesselSidebar/actions/TrackRequest/index.tsx b/frontend/src/features/VesselSidebar/actions/TrackRequest/index.tsx index 04a61a8c57..2acb8b510a 100644 --- a/frontend/src/features/VesselSidebar/actions/TrackRequest/index.tsx +++ b/frontend/src/features/VesselSidebar/actions/TrackRequest/index.tsx @@ -22,7 +22,7 @@ type TrackRequestProps = { } export function TrackRequest({ isSidebarOpen }: TrackRequestProps) { const dispatch = useMainAppDispatch() - const { rightMenuIsOpen } = useMainAppSelector(state => state.global) + const { rightMenuIsOpen } = useMainAppSelector(state => state.mainWindow) const { defaultVesselTrackDepth } = useMainAppSelector(state => state.map) const { selectedVesselTrackRequest } = useMainAppSelector(state => state.vessel) const { selectedVesselIdentity } = useMainAppSelector(state => state.vessel) diff --git a/frontend/src/features/VesselSidebar/actions/animate_to_track/index.tsx b/frontend/src/features/VesselSidebar/actions/animate_to_track/index.tsx index f6e65fee36..72dead9843 100644 --- a/frontend/src/features/VesselSidebar/actions/animate_to_track/index.tsx +++ b/frontend/src/features/VesselSidebar/actions/animate_to_track/index.tsx @@ -7,7 +7,7 @@ import ShowTrackSVG from '../../../icons/Bouton_afficher_toute_la_piste.svg?reac import { VesselSidebarActionButton } from '../VesselSidebarActionButton' export function AnimateToTrack({ isSidebarOpen }) { - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const selectedVesselPositions = useMainAppSelector(state => state.vessel.selectedVesselPositions) const dispatch = useMainAppDispatch() diff --git a/frontend/src/features/VesselSidebar/actions/hide_non_selected_vessels/index.tsx b/frontend/src/features/VesselSidebar/actions/hide_non_selected_vessels/index.tsx index 3497614d5f..84e5721b7a 100644 --- a/frontend/src/features/VesselSidebar/actions/hide_non_selected_vessels/index.tsx +++ b/frontend/src/features/VesselSidebar/actions/hide_non_selected_vessels/index.tsx @@ -10,7 +10,7 @@ import { VesselSidebarActionButton } from '../VesselSidebarActionButton' export function HideNonSelectedVessels({ isSidebarOpen }) { const dispatch = useMainAppDispatch() - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const hideNonSelectedVessels = useMainAppSelector(state => state.vessel.hideNonSelectedVessels) const selectedVesselPositions = useMainAppSelector(state => state.vessel.selectedVesselPositions) diff --git a/frontend/src/features/VesselSidebar/actions/show_fishing_activities/index.tsx b/frontend/src/features/VesselSidebar/actions/show_fishing_activities/index.tsx index 0107d1dd66..41c4155079 100644 --- a/frontend/src/features/VesselSidebar/actions/show_fishing_activities/index.tsx +++ b/frontend/src/features/VesselSidebar/actions/show_fishing_activities/index.tsx @@ -11,7 +11,7 @@ import { VesselSidebarActionButton } from '../VesselSidebarActionButton' export function ShowFishingActivitiesOnMap({ isSidebarOpen }) { const dispatch = useMainAppDispatch() - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const { selectedVesselIdentity, selectedVesselPositions } = useMainAppSelector(state => state.vessel) const { areFishingActivitiesShowedOnMap, fishingActivities, fishingActivitiesShowedOnMap } = useMainAppSelector( state => state.fishingActivities diff --git a/frontend/src/features/VesselSidebar/index.tsx b/frontend/src/features/VesselSidebar/index.tsx index 550a0dc25d..55f20aba86 100644 --- a/frontend/src/features/VesselSidebar/index.tsx +++ b/frontend/src/features/VesselSidebar/index.tsx @@ -11,7 +11,7 @@ import { useMainAppSelector } from '../../hooks/useMainAppSelector' import { MapComponent } from '../commonStyles/MapComponent' export function VesselSidebar() { - const rightMenuIsOpen = useMainAppSelector(state => state.global.rightMenuIsOpen) + const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const isFocusedOnVesselSearch = useMainAppSelector(state => state.vessel.isFocusedOnVesselSearch) const [isFirstLoad, setIsFirstLoad] = useState(false) diff --git a/frontend/src/features/commonComponents/ErrorToastNotification.tsx b/frontend/src/features/commonComponents/ErrorToastNotification.tsx index 492fb1422e..714ea7087d 100644 --- a/frontend/src/features/commonComponents/ErrorToastNotification.tsx +++ b/frontend/src/features/commonComponents/ErrorToastNotification.tsx @@ -14,7 +14,7 @@ export function ErrorToastNotification() { | (Error & { type: ErrorType }) - | null = useMainAppSelector(state => state.global.error) + | null = useMainAppSelector(state => state.mainWindow.error) useEffect(() => { if (!error || (error.type && error.type === ErrorType.INFO_AND_HIDDEN)) { diff --git a/frontend/src/features/commonStyles/MapComponent.tsx b/frontend/src/features/commonStyles/MapComponent.tsx index 705be1433f..851ea4334f 100644 --- a/frontend/src/features/commonStyles/MapComponent.tsx +++ b/frontend/src/features/commonStyles/MapComponent.tsx @@ -1,7 +1,5 @@ import styled from 'styled-components' -import { useMainAppSelector } from '../../hooks/useMainAppSelector' - import type { ReactNode } from 'react' type MapComponentStyleType = { @@ -10,11 +8,8 @@ type MapComponentStyleType = { isHidden?: boolean | undefined } export function MapComponent({ children, className, isHidden, ...props }: MapComponentStyleType) { - const healthcheckTextWarning = useMainAppSelector(state => state.global.healthcheckTextWarning) - return ( ` - margin-top: ${p => (p.$hasHealthcheckTextWarning ? 50 : 0)}px; visibility: ${p => (p.$isHidden ? 'hidden' : 'visible')}; ` diff --git a/frontend/src/features/map/BaseMap.tsx b/frontend/src/features/map/BaseMap.tsx index e4d1075ed2..fbe2e9a275 100644 --- a/frontend/src/features/map/BaseMap.tsx +++ b/frontend/src/features/map/BaseMap.tsx @@ -43,17 +43,16 @@ export function BaseMap({ showAttributions, showCoordinates }: BaseMapProps) { - const { animateToRegulatoryLayer } = useMainAppSelector(state => state.map) + const isAnimating = useRef(false) + const isInitRenderDone = useRef(false) + const mapElement = useRef(null) - const { healthcheckTextWarning, previewFilteredVesselsMode } = useMainAppSelector(state => state.global) const dispatch = useMainAppDispatch() + const animateToRegulatoryLayer = useMainAppSelector(state => state.map.animateToRegulatoryLayer) + const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) - const isAnimating = useRef(false) - const isInitRenderDone = useRef(false) const [cursorCoordinates, setCursorCoordinates] = useState(undefined) - const mapElement = useRef() - const handleMapClick = useCallback( (event, _map: OpenLayerMap) => { if (!event || !_map) { @@ -151,7 +150,7 @@ export function BaseMap({ ) useEffect(() => { - monitorfishMap.setTarget(mapElement.current) + monitorfishMap.setTarget(mapElement.current ?? undefined) monitorfishMap.on('click', event => handleMapClick(event, monitorfishMap)) monitorfishMap.on('pointermove', event => throttleAndHandlePointerMove(event, monitorfishMap)) @@ -223,12 +222,7 @@ export function BaseMap({ return ( - + {showCoordinates && } {showAttributions && } {Children.map(children, child => child)} @@ -238,14 +232,13 @@ export function BaseMap({ const MapWrapper = styled.div` display: flex; - flex: 1; + height: 100%; ` const MapContainer = styled.div<{ - $hasHealthcheckTextWarning: boolean $isPreviewFilteredVesselsMode: boolean }>` - height: ${p => (p.$hasHealthcheckTextWarning || p.$isPreviewFilteredVesselsMode ? 'calc(100vh - 50px)' : '100vh')}; + height: ${p => (p.$isPreviewFilteredVesselsMode ? 'calc(100vh - 50px)' : '100vh')}; width: 100%; overflow-y: hidden; overflow-x: hidden; diff --git a/frontend/src/features/map/layers/Vessel/VesselAlertAndBeaconMalfunctionLayer.jsx b/frontend/src/features/map/layers/Vessel/VesselAlertAndBeaconMalfunctionLayer.jsx index 06a10920fd..1845e21987 100644 --- a/frontend/src/features/map/layers/Vessel/VesselAlertAndBeaconMalfunctionLayer.jsx +++ b/frontend/src/features/map/layers/Vessel/VesselAlertAndBeaconMalfunctionLayer.jsx @@ -1,59 +1,52 @@ -import React, { useEffect, useRef } from 'react' -import { useSelector } from 'react-redux' -import VectorSource from 'ol/source/Vector' import Feature from 'ol/Feature' import Point from 'ol/geom/Point' import { Vector } from 'ol/layer' -import { LayerProperties } from '../../../../domain/entities/layers/constants' +import VectorSource from 'ol/source/Vector' +import React, { useEffect, useRef } from 'react' +import { useSelector } from 'react-redux' import { getVesselAlertAndBeaconMalfunctionStyle } from './style' +import { LayerProperties } from '../../../../domain/entities/layers/constants' import { getVesselCompositeIdentifier, vesselIsShowed } from '../../../../domain/entities/vessel/vessel' import { useIsSuperUser } from '../../../../auth/hooks/useIsSuperUser' import { monitorfishMap } from '../../monitorfishMap' -const VesselAlertAndBeaconMalfunctionLayer = () => { +function VesselAlertAndBeaconMalfunctionLayer() { const isSuperUser = useIsSuperUser() - const { - vessels, - hideNonSelectedVessels, - selectedVesselIdentity, - vesselsTracksShowed - } = useSelector(state => state.vessel) + const { hideNonSelectedVessels, selectedVesselIdentity, vessels, vesselsTracksShowed } = useSelector( + state => state.vessel + ) - const { - nonFilteredVesselsAreHidden - } = useSelector(state => state.filter) + const { nonFilteredVesselsAreHidden } = useSelector(state => state.filter) - const { - previewFilteredVesselsMode - } = useSelector(state => state.global) + const { previewFilteredVesselsMode } = useSelector(state => state.mainWindow) - const { - hideVesselsAtPort - } = useSelector(state => state.map) + const { hideVesselsAtPort } = useSelector(state => state.map) const vectorSourceRef = useRef(null) - function getVectorSource () { + function getVectorSource() { if (vectorSourceRef.current === null) { vectorSourceRef.current = new VectorSource({ features: [], wrapX: false }) } + return vectorSourceRef.current } const layerRef = useRef(null) - function getLayer () { + function getLayer() { if (layerRef.current === null) { layerRef.current = new Vector({ source: getVectorSource(), - zIndex: LayerProperties.VESSEL_BEACON_MALFUNCTION.zIndex, + style: (_, resolution) => getVesselAlertAndBeaconMalfunctionStyle(resolution), updateWhileAnimating: true, updateWhileInteracting: true, - style: (_, resolution) => getVesselAlertAndBeaconMalfunctionStyle(resolution) + zIndex: LayerProperties.VESSEL_BEACON_MALFUNCTION.zIndex }) } + return layerRef.current } @@ -71,17 +64,34 @@ const VesselAlertAndBeaconMalfunctionLayer = () => { useEffect(() => { if (isSuperUser && vessels?.length) { const features = vessels.reduce((_features, vessel) => { - if (!vessel.hasBeaconMalfunction) return _features - if (!vessel.vesselProperties.hasAlert) return _features - if (nonFilteredVesselsAreHidden && !vessel.isFiltered) return _features - if (previewFilteredVesselsMode && !vessel.filterPreview) return _features - if (hideVesselsAtPort && vessel.isAtPort) return _features - if (hideNonSelectedVessels && !vesselIsShowed(vessel.vesselProperties, vesselsTracksShowed, selectedVesselIdentity)) return _features + if (!vessel.hasBeaconMalfunction) { + return _features + } + if (!vessel.vesselProperties.hasAlert) { + return _features + } + if (nonFilteredVesselsAreHidden && !vessel.isFiltered) { + return _features + } + if (previewFilteredVesselsMode && !vessel.filterPreview) { + return _features + } + if (hideVesselsAtPort && vessel.isAtPort) { + return _features + } + if ( + hideNonSelectedVessels && + !vesselIsShowed(vessel.vesselProperties, vesselsTracksShowed, selectedVesselIdentity) + ) { + return _features + } const feature = new Feature({ geometry: new Point(vessel.coordinates) }) - feature.setId(`${LayerProperties.VESSEL_BEACON_MALFUNCTION.code}:${getVesselCompositeIdentifier(vessel.vesselProperties)}`) + feature.setId( + `${LayerProperties.VESSEL_BEACON_MALFUNCTION.code}:${getVesselCompositeIdentifier(vessel.vesselProperties)}` + ) _features.push(feature) return _features diff --git a/frontend/src/features/map/layers/Vessel/VesselAlertLayer.jsx b/frontend/src/features/map/layers/Vessel/VesselAlertLayer.jsx index f48d4de0ce..78b0a2eff1 100644 --- a/frontend/src/features/map/layers/Vessel/VesselAlertLayer.jsx +++ b/frontend/src/features/map/layers/Vessel/VesselAlertLayer.jsx @@ -1,12 +1,12 @@ -import React, { useEffect, useRef } from 'react' -import { useSelector } from 'react-redux' -import VectorSource from 'ol/source/Vector' import Feature from 'ol/Feature' import Point from 'ol/geom/Point' import { Vector } from 'ol/layer' -import { LayerProperties } from '../../../../domain/entities/layers/constants' +import VectorSource from 'ol/source/Vector' +import React, { useEffect, useRef } from 'react' +import { useSelector } from 'react-redux' import { getVesselAlertStyle } from './style' +import { LayerProperties } from '../../../../domain/entities/layers/constants' import { getVesselCompositeIdentifier, getVesselLastPositionVisibilityDates, @@ -16,52 +16,44 @@ import { import { useIsSuperUser } from '../../../../auth/hooks/useIsSuperUser' import { monitorfishMap } from '../../monitorfishMap' -const VesselAlertLayer = () => { +function VesselAlertLayer() { const isSuperUser = useIsSuperUser() - const { - vessels, - hideNonSelectedVessels, - selectedVesselIdentity, - vesselsTracksShowed - } = useSelector(state => state.vessel) + const { hideNonSelectedVessels, selectedVesselIdentity, vessels, vesselsTracksShowed } = useSelector( + state => state.vessel + ) - const { - nonFilteredVesselsAreHidden - } = useSelector(state => state.filter) + const { nonFilteredVesselsAreHidden } = useSelector(state => state.filter) - const { - previewFilteredVesselsMode - } = useSelector(state => state.global) + const { previewFilteredVesselsMode } = useSelector(state => state.mainWindow) - const { - vesselsLastPositionVisibility, - hideVesselsAtPort - } = useSelector(state => state.map) + const { hideVesselsAtPort, vesselsLastPositionVisibility } = useSelector(state => state.map) const vectorSourceRef = useRef(null) const layerRef = useRef(null) - function getVectorSource () { + function getVectorSource() { if (vectorSourceRef.current === null) { vectorSourceRef.current = new VectorSource({ features: [], wrapX: false }) } + return vectorSourceRef.current } - function getLayer () { + function getLayer() { if (layerRef.current === null) { layerRef.current = new Vector({ source: getVectorSource(), - zIndex: LayerProperties.VESSEL_ALERT.zIndex, + style: (_, resolution) => getVesselAlertStyle(resolution), updateWhileAnimating: true, updateWhileInteracting: true, - style: (_, resolution) => getVesselAlertStyle(resolution) + zIndex: LayerProperties.VESSEL_ALERT.zIndex }) } + return layerRef.current } @@ -78,16 +70,34 @@ const VesselAlertLayer = () => { useEffect(() => { if (isSuperUser && vessels?.length) { - const { vesselIsHidden, vesselIsOpacityReduced } = getVesselLastPositionVisibilityDates(vesselsLastPositionVisibility) + const { vesselIsHidden, vesselIsOpacityReduced } = + getVesselLastPositionVisibilityDates(vesselsLastPositionVisibility) const features = vessels.reduce((features, vessel) => { - if (!vessel.vesselProperties.hasAlert) return features - if (vessel.hasBeaconMalfunction) return features - if (nonFilteredVesselsAreHidden && !vessel.isFiltered) return features - if (previewFilteredVesselsMode && !vessel.filterPreview) return features - if (hideVesselsAtPort && vessel.isAtPort) return features - if (hideNonSelectedVessels && !vesselIsShowed(vessel.vesselProperties, vesselsTracksShowed, selectedVesselIdentity)) return features - if (!Vessel.getVesselOpacity(vessel.vesselProperties.dateTime, vesselIsHidden, vesselIsOpacityReduced)) return features + if (!vessel.vesselProperties.hasAlert) { + return features + } + if (vessel.hasBeaconMalfunction) { + return features + } + if (nonFilteredVesselsAreHidden && !vessel.isFiltered) { + return features + } + if (previewFilteredVesselsMode && !vessel.filterPreview) { + return features + } + if (hideVesselsAtPort && vessel.isAtPort) { + return features + } + if ( + hideNonSelectedVessels && + !vesselIsShowed(vessel.vesselProperties, vesselsTracksShowed, selectedVesselIdentity) + ) { + return features + } + if (!Vessel.getVesselOpacity(vessel.vesselProperties.dateTime, vesselIsHidden, vesselIsOpacityReduced)) { + return features + } const feature = new Feature({ geometry: new Point(vessel.coordinates) diff --git a/frontend/src/features/map/layers/Vessel/VesselBeaconMalfunctionLayer.jsx b/frontend/src/features/map/layers/Vessel/VesselBeaconMalfunctionLayer.jsx index 09d73fb28a..c4467caa93 100644 --- a/frontend/src/features/map/layers/Vessel/VesselBeaconMalfunctionLayer.jsx +++ b/frontend/src/features/map/layers/Vessel/VesselBeaconMalfunctionLayer.jsx @@ -1,60 +1,53 @@ -import React, { useEffect, useRef } from 'react' -import { useSelector } from 'react-redux' -import VectorSource from 'ol/source/Vector' import Feature from 'ol/Feature' import Point from 'ol/geom/Point' import { Vector } from 'ol/layer' -import { LayerProperties } from '../../../../domain/entities/layers/constants' +import VectorSource from 'ol/source/Vector' +import React, { useEffect, useRef } from 'react' +import { useSelector } from 'react-redux' import { getVesselBeaconMalfunctionStyle } from './style' +import { LayerProperties } from '../../../../domain/entities/layers/constants' import { getVesselCompositeIdentifier, vesselIsShowed } from '../../../../domain/entities/vessel/vessel' import { useIsSuperUser } from '../../../../auth/hooks/useIsSuperUser' import { monitorfishMap } from '../../monitorfishMap' -const VesselBeaconMalfunctionLayer = () => { +function VesselBeaconMalfunctionLayer() { const isSuperUser = useIsSuperUser() - const { - vessels, - hideNonSelectedVessels, - vesselsTracksShowed, - selectedVesselIdentity - } = useSelector(state => state.vessel) + const { hideNonSelectedVessels, selectedVesselIdentity, vessels, vesselsTracksShowed } = useSelector( + state => state.vessel + ) - const { - nonFilteredVesselsAreHidden - } = useSelector(state => state.filter) + const { nonFilteredVesselsAreHidden } = useSelector(state => state.filter) - const { - previewFilteredVesselsMode - } = useSelector(state => state.global) + const { previewFilteredVesselsMode } = useSelector(state => state.mainWindow) - const { - hideVesselsAtPort - } = useSelector(state => state.map) + const { hideVesselsAtPort } = useSelector(state => state.map) const vectorSourceRef = useRef(null) - function getVectorSource () { + function getVectorSource() { if (vectorSourceRef.current === null) { vectorSourceRef.current = new VectorSource({ features: [], wrapX: false }) } + return vectorSourceRef.current } const layerRef = useRef(null) - function getLayer () { + function getLayer() { if (layerRef.current === null) { layerRef.current = new Vector({ source: getVectorSource(), - zIndex: LayerProperties.VESSEL_BEACON_MALFUNCTION.zIndex, + style: (_, resolution) => getVesselBeaconMalfunctionStyle(resolution), updateWhileAnimating: true, updateWhileInteracting: true, - style: (_, resolution) => getVesselBeaconMalfunctionStyle(resolution) + zIndex: LayerProperties.VESSEL_BEACON_MALFUNCTION.zIndex }) } + return layerRef.current } @@ -72,17 +65,34 @@ const VesselBeaconMalfunctionLayer = () => { useEffect(() => { if (isSuperUser && vessels?.length) { const features = vessels.reduce((_features, vessel) => { - if (!vessel.hasBeaconMalfunction) return _features - if (vessel.vesselProperties.hasAlert) return _features - if (nonFilteredVesselsAreHidden && !vessel.isFiltered) return _features - if (previewFilteredVesselsMode && !vessel.filterPreview) return _features - if (hideVesselsAtPort && vessel.isAtPort) return _features - if (hideNonSelectedVessels && !vesselIsShowed(vessel.vesselProperties, vesselsTracksShowed, selectedVesselIdentity)) return _features + if (!vessel.hasBeaconMalfunction) { + return _features + } + if (vessel.vesselProperties.hasAlert) { + return _features + } + if (nonFilteredVesselsAreHidden && !vessel.isFiltered) { + return _features + } + if (previewFilteredVesselsMode && !vessel.filterPreview) { + return _features + } + if (hideVesselsAtPort && vessel.isAtPort) { + return _features + } + if ( + hideNonSelectedVessels && + !vesselIsShowed(vessel.vesselProperties, vesselsTracksShowed, selectedVesselIdentity) + ) { + return _features + } const feature = new Feature({ geometry: new Point(vessel.coordinates) }) - feature.setId(`${LayerProperties.VESSEL_BEACON_MALFUNCTION.code}:${getVesselCompositeIdentifier(vessel.vesselProperties)}`) + feature.setId( + `${LayerProperties.VESSEL_BEACON_MALFUNCTION.code}:${getVesselCompositeIdentifier(vessel.vesselProperties)}` + ) _features.push(feature) return _features diff --git a/frontend/src/features/map/layers/Vessel/VesselEstimatedPositionLayer.jsx b/frontend/src/features/map/layers/Vessel/VesselEstimatedPositionLayer.jsx index 19853ab0b4..85e9e2aa99 100644 --- a/frontend/src/features/map/layers/Vessel/VesselEstimatedPositionLayer.jsx +++ b/frontend/src/features/map/layers/Vessel/VesselEstimatedPositionLayer.jsx @@ -1,65 +1,57 @@ +import { Vector } from 'ol/layer' +import VectorSource from 'ol/source/Vector' import React, { useEffect, useRef } from 'react' import { useSelector } from 'react-redux' -import VectorSource from 'ol/source/Vector' -import { LayerProperties } from '../../../../domain/entities/layers/constants' + import { EstimatedPosition } from '../../../../domain/entities/estimatedPosition' +import { LayerProperties } from '../../../../domain/entities/layers/constants' import { getVesselLastPositionVisibilityDates, Vessel, vesselIsShowed } from '../../../../domain/entities/vessel/vessel' -import { Vector } from 'ol/layer' -import { getEstimatedPositionStyle } from '../styles/vesselEstimatedPosition.style' import { monitorfishMap } from '../../monitorfishMap' +import { getEstimatedPositionStyle } from '../styles/vesselEstimatedPosition.style' -const VesselEstimatedPositionLayer = () => { - const { - vessels, - hideNonSelectedVessels, - vesselsTracksShowed, - selectedVesselIdentity - } = useSelector(state => state.vessel) +function VesselEstimatedPositionLayer() { + const { hideNonSelectedVessels, selectedVesselIdentity, vessels, vesselsTracksShowed } = useSelector( + state => state.vessel + ) - const { - nonFilteredVesselsAreHidden - } = useSelector(state => state.filter) + const { nonFilteredVesselsAreHidden } = useSelector(state => state.filter) - const { - previewFilteredVesselsMode - } = useSelector(state => state.global) + const { previewFilteredVesselsMode } = useSelector(state => state.mainWindow) - const { - selectedBaseLayer, - showingVesselsEstimatedPositions, - vesselsLastPositionVisibility, - hideVesselsAtPort - } = useSelector(state => state.map) + const { hideVesselsAtPort, selectedBaseLayer, showingVesselsEstimatedPositions, vesselsLastPositionVisibility } = + useSelector(state => state.map) const vectorSourceRef = useRef(null) const layerRef = useRef(null) - function getVectorSource () { + function getVectorSource() { if (vectorSourceRef.current === null) { vectorSourceRef.current = new VectorSource({ features: [], wrapX: false }) } + return vectorSourceRef.current } - function getLayer () { + function getLayer() { if (layerRef.current === null) { layerRef.current = new Vector({ renderBuffer: 4, source: getVectorSource(), - zIndex: LayerProperties.VESSEL_ESTIMATED_POSITION.zIndex, + style: feature => getEstimatedPositionStyle(feature), updateWhileAnimating: true, updateWhileInteracting: true, - style: feature => getEstimatedPositionStyle(feature) + zIndex: LayerProperties.VESSEL_ESTIMATED_POSITION.zIndex }) } + return layerRef.current } useEffect(() => { - function addLayerToMap () { + function addLayerToMap() { getLayer().name = LayerProperties.VESSEL_ESTIMATED_POSITION.code monitorfishMap.getLayers().push(getLayer()) } @@ -77,23 +69,29 @@ const VesselEstimatedPositionLayer = () => { } if (vessels && showingVesselsEstimatedPositions) { - function createEstimatedTrackFeatures (vessel, options) { - const { - isAtPort, - isFiltered, - filterPreview - } = vessel - - if (nonFilteredVesselsAreHidden && !isFiltered) return null - if (previewFilteredVesselsMode && !filterPreview) return null - if (hideVesselsAtPort && isAtPort) return null - - options.hideNonSelectedVessels = hideNonSelectedVessels && !vesselIsShowed(vessel.vesselProperties, vesselsTracksShowed, selectedVesselIdentity) + function createEstimatedTrackFeatures(vessel, options) { + const { filterPreview, isAtPort, isFiltered } = vessel + + if (nonFilteredVesselsAreHidden && !isFiltered) { + return null + } + if (previewFilteredVesselsMode && !filterPreview) { + return null + } + if (hideVesselsAtPort && isAtPort) { + return null + } + + options.hideNonSelectedVessels = + hideNonSelectedVessels && + !vesselIsShowed(vessel.vesselProperties, vesselsTracksShowed, selectedVesselIdentity) + return EstimatedPosition.getFeatures(vessel, options) } const isLight = Vessel.iconIsLight(selectedBaseLayer) - const { vesselIsHidden, vesselIsOpacityReduced } = getVesselLastPositionVisibilityDates(vesselsLastPositionVisibility) + const { vesselIsHidden, vesselIsOpacityReduced } = + getVesselLastPositionVisibilityDates(vesselsLastPositionVisibility) const options = { isLight, vesselIsHidden, diff --git a/frontend/src/features/map/layers/Vessel/VesselInfractionSuspicionLayer.jsx b/frontend/src/features/map/layers/Vessel/VesselInfractionSuspicionLayer.jsx index c28cf204a3..744e622ba3 100644 --- a/frontend/src/features/map/layers/Vessel/VesselInfractionSuspicionLayer.jsx +++ b/frontend/src/features/map/layers/Vessel/VesselInfractionSuspicionLayer.jsx @@ -1,12 +1,12 @@ -import React, { useEffect, useRef } from 'react' -import { useSelector } from 'react-redux' -import VectorSource from 'ol/source/Vector' import Feature from 'ol/Feature' import Point from 'ol/geom/Point' import { Vector } from 'ol/layer' -import { LayerProperties } from '../../../../domain/entities/layers/constants' +import VectorSource from 'ol/source/Vector' +import React, { useEffect, useRef } from 'react' +import { useSelector } from 'react-redux' import { getVesselInfractionSuspicionStyle } from './style' +import { LayerProperties } from '../../../../domain/entities/layers/constants' import { getVesselCompositeIdentifier, getVesselLastPositionVisibilityDates, @@ -16,52 +16,44 @@ import { import { useIsSuperUser } from '../../../../auth/hooks/useIsSuperUser' import { monitorfishMap } from '../../monitorfishMap' -const VesselInfractionSuspicionLayer = () => { +function VesselInfractionSuspicionLayer() { const isSuperUser = useIsSuperUser() - const { - vessels, - hideNonSelectedVessels, - selectedVesselIdentity, - vesselsTracksShowed - } = useSelector(state => state.vessel) + const { hideNonSelectedVessels, selectedVesselIdentity, vessels, vesselsTracksShowed } = useSelector( + state => state.vessel + ) - const { - nonFilteredVesselsAreHidden - } = useSelector(state => state.filter) + const { nonFilteredVesselsAreHidden } = useSelector(state => state.filter) - const { - previewFilteredVesselsMode - } = useSelector(state => state.global) + const { previewFilteredVesselsMode } = useSelector(state => state.mainWindow) - const { - vesselsLastPositionVisibility, - hideVesselsAtPort - } = useSelector(state => state.map) + const { hideVesselsAtPort, vesselsLastPositionVisibility } = useSelector(state => state.map) const vectorSourceRef = useRef(null) const layerRef = useRef(null) - function getVectorSource () { + function getVectorSource() { if (vectorSourceRef.current === null) { vectorSourceRef.current = new VectorSource({ features: [], wrapX: false }) } + return vectorSourceRef.current } - function getLayer () { + function getLayer() { if (layerRef.current === null) { layerRef.current = new Vector({ source: getVectorSource(), - zIndex: LayerProperties.VESSEL_INFRACTION_SUSPICION.zIndex, + style: (_, resolution) => getVesselInfractionSuspicionStyle(resolution), updateWhileAnimating: true, updateWhileInteracting: true, - style: (_, resolution) => getVesselInfractionSuspicionStyle(resolution) + zIndex: LayerProperties.VESSEL_INFRACTION_SUSPICION.zIndex }) } + return layerRef.current } @@ -78,20 +70,38 @@ const VesselInfractionSuspicionLayer = () => { useEffect(() => { if (isSuperUser && vessels?.length) { - const { vesselIsHidden, vesselIsOpacityReduced } = getVesselLastPositionVisibilityDates(vesselsLastPositionVisibility) + const { vesselIsHidden, vesselIsOpacityReduced } = + getVesselLastPositionVisibilityDates(vesselsLastPositionVisibility) const features = vessels.reduce((features, vessel) => { - if (!vessel.vesselProperties.hasInfractionSuspicion) return features - if (nonFilteredVesselsAreHidden && !vessel.isFiltered) return features - if (previewFilteredVesselsMode && !vessel.filterPreview) return features - if (hideVesselsAtPort && vessel.isAtPort) return features - if (hideNonSelectedVessels && !vesselIsShowed(vessel.vesselProperties, vesselsTracksShowed, selectedVesselIdentity)) return features - if (!Vessel.getVesselOpacity(vessel.vesselProperties.dateTime, vesselIsHidden, vesselIsOpacityReduced)) return features + if (!vessel.vesselProperties.hasInfractionSuspicion) { + return features + } + if (nonFilteredVesselsAreHidden && !vessel.isFiltered) { + return features + } + if (previewFilteredVesselsMode && !vessel.filterPreview) { + return features + } + if (hideVesselsAtPort && vessel.isAtPort) { + return features + } + if ( + hideNonSelectedVessels && + !vesselIsShowed(vessel.vesselProperties, vesselsTracksShowed, selectedVesselIdentity) + ) { + return features + } + if (!Vessel.getVesselOpacity(vessel.vesselProperties.dateTime, vesselIsHidden, vesselIsOpacityReduced)) { + return features + } const feature = new Feature({ geometry: new Point(vessel.coordinates) }) - feature.setId(`${LayerProperties.VESSEL_INFRACTION_SUSPICION.code}:${getVesselCompositeIdentifier(vessel.vesselProperties)}`) + feature.setId( + `${LayerProperties.VESSEL_INFRACTION_SUSPICION.code}:${getVesselCompositeIdentifier(vessel.vesselProperties)}` + ) features.push(feature) return features diff --git a/frontend/src/features/map/layers/Vessel/VesselsLabelsLayer.tsx b/frontend/src/features/map/layers/Vessel/VesselsLabelsLayer.tsx index 6e7636d281..a7f8ec87fa 100644 --- a/frontend/src/features/map/layers/Vessel/VesselsLabelsLayer.tsx +++ b/frontend/src/features/map/layers/Vessel/VesselsLabelsLayer.tsx @@ -39,7 +39,7 @@ export function VesselsLabelsLayer({ mapMovingAndZoomEvent }) { const vessels = useMainAppSelector(state => state.vessel.vessels) const vesselsTracksShowed = useMainAppSelector(state => state.vessel.vesselsTracksShowed) const areVesselsDisplayed = useMainAppSelector(state => state.displayedComponent.areVesselsDisplayed) - const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) + const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) const hideVesselsAtPort = useMainAppSelector(state => state.map.hideVesselsAtPort) const riskFactorShowedOnMap = useMainAppSelector(state => state.map.riskFactorShowedOnMap) diff --git a/frontend/src/features/map/layers/Vessel/VesselsLayer/index.tsx b/frontend/src/features/map/layers/Vessel/VesselsLayer/index.tsx index 061a16959f..8ea65c1441 100644 --- a/frontend/src/features/map/layers/Vessel/VesselsLayer/index.tsx +++ b/frontend/src/features/map/layers/Vessel/VesselsLayer/index.tsx @@ -30,7 +30,7 @@ function UnmemoizedVesselsLayer() { const selectedBaseLayer = useMainAppSelector(state => state.map.selectedBaseLayer) const vesselsLastPositionVisibility = useMainAppSelector(state => state.map.vesselsLastPositionVisibility) - const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) + const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) const { filterColor, filters, nonFilteredVesselsAreHidden, showedFilter } = useMainAppSelector(state => { const nextShowedFilter = state.filter?.filters?.find(filter => filter.showed) diff --git a/frontend/src/features/preview_filtered_vessels/PreviewFilteredVessels.jsx b/frontend/src/features/preview_filtered_vessels/PreviewFilteredVessels.jsx index 0676f5884e..195a124a96 100644 --- a/frontend/src/features/preview_filtered_vessels/PreviewFilteredVessels.jsx +++ b/frontend/src/features/preview_filtered_vessels/PreviewFilteredVessels.jsx @@ -1,23 +1,24 @@ import React from 'react' -import styled from 'styled-components' import { useDispatch, useSelector } from 'react-redux' +import styled from 'styled-components' + import { COLORS } from '../../constants/constants' import BackToVesselsListSVG from '../icons/Fleche_navigation_marees_gainsboro.svg?react' -import { setPreviewFilteredVesselsMode } from '../../domain/shared_slices/Global' +import { setPreviewFilteredVesselsMode } from '../MainWindow/slice' -const PreviewFilteredVessels = () => { +function PreviewFilteredVessels() { const dispatch = useDispatch() - const { previewFilteredVesselsMode } = useSelector(state => state.global) + const { previewFilteredVesselsMode } = useSelector(state => state.mainWindow) return ( <> {previewFilteredVesselsMode ? ( { dispatch(setPreviewFilteredVesselsMode(false)) }} - data-cy={'back-to-vessels-list'} > diff --git a/frontend/src/hooks/useClickOutsideWhenOpenedWithinRef.jsx b/frontend/src/hooks/useClickOutsideWhenOpenedWithinRef.jsx deleted file mode 100644 index 820decbe34..0000000000 --- a/frontend/src/hooks/useClickOutsideWhenOpenedWithinRef.jsx +++ /dev/null @@ -1,34 +0,0 @@ -import { useEffect, useState } from 'react' - -export const useClickOutsideWhenOpenedWithinRef = (ref, isOpened, baseRef) => { - const [clicked, setClicked] = useState(null) - - useEffect(() => { - function handleClickOutside (event) { - if (ref.current && !ref.current.contains(event.target)) { - setClicked({}) - } else { - setClicked(null) - } - } - - // Bind the event listener - if (isOpened) { - if (baseRef) { - baseRef.current?.addEventListener('mousedown', handleClickOutside) - } else { - document.addEventListener('mousedown', handleClickOutside) - } - } - return () => { - // Unbind the event listener on clean up - if (baseRef) { - baseRef.current?.removeEventListener('mousedown', handleClickOutside) - } else { - document.addEventListener('mousedown', handleClickOutside) - } - } - }, [ref, isOpened]) - - return clicked -} diff --git a/frontend/src/hooks/useClickOutsideWhenOpenedWithinRef.tsx b/frontend/src/hooks/useClickOutsideWhenOpenedWithinRef.tsx new file mode 100644 index 0000000000..dda88c8d6d --- /dev/null +++ b/frontend/src/hooks/useClickOutsideWhenOpenedWithinRef.tsx @@ -0,0 +1,48 @@ +import { useEffect, useState, type MutableRefObject } from 'react' + +export const useClickOutsideWhenOpenedWithinRef = ( + ref: MutableRefObject, + isOpened: boolean, + // TODO Should be `MutableRefObject | undefined`. + baseRef: MutableRefObject | undefined +): {} | null => { + const [clicked, setClicked] = useState<{} | null>(null) + + useEffect( + () => { + function handleClickOutside(event) { + if (ref.current && !ref.current.contains(event.target)) { + setClicked({}) + } else { + setClicked(null) + } + } + + // Bind the event listener + if (isOpened) { + if (baseRef) { + baseRef.current?.addEventListener('mousedown', handleClickOutside) + } else { + document.addEventListener('mousedown', handleClickOutside) + } + } + + return () => { + // Unbind the event listener on clean up + if (baseRef) { + // TODO Not so sure about this disabled ESLint rule, quick workaround for TS migration. + // eslint-disable-next-line react-hooks/exhaustive-deps + baseRef.current?.removeEventListener('mousedown', handleClickOutside) + } else { + document.addEventListener('mousedown', handleClickOutside) + } + } + }, + + // TODO Not so sure about this disabled ESLint rule, quick workaround for TS migration. + // eslint-disable-next-line react-hooks/exhaustive-deps + [ref, isOpened] + ) + + return clicked +} diff --git a/frontend/src/store/reducers.ts b/frontend/src/store/reducers.ts index 05de0b67bf..5c6567dc3b 100644 --- a/frontend/src/store/reducers.ts +++ b/frontend/src/store/reducers.ts @@ -15,7 +15,6 @@ import { displayedErrorReducer } from '../domain/shared_slices/DisplayedError' import { favoriteVesselReducer } from '../domain/shared_slices/FavoriteVessel' import { filterReducer } from '../domain/shared_slices/Filter' import { gearReducer } from '../domain/shared_slices/Gear' -import { globalSliceReducer } from '../domain/shared_slices/Global' import { infractionReducer } from '../domain/shared_slices/Infraction' import layer from '../domain/shared_slices/Layer' import { mapReducer } from '../domain/shared_slices/Map' @@ -26,6 +25,7 @@ import { controlUnitDialogReducer } from '../features/ControlUnit/components/Con import { controlUnitListDialogPersistedReducer } from '../features/ControlUnit/components/ControlUnitListDialog/slice' import { customZoneReducer, type CustomZoneState } from '../features/CustomZone/slice' import { logbookReducer } from '../features/Logbook/slice' +import { mainWindowSliceReducer } from '../features/MainWindow/slice' import { missionFormReducer } from '../features/Mission/components/MissionForm/slice' import { missionListReducer, type MissionListState } from '../features/Mission/components/MissionList/slice' import { priorNotificationReducer, type PriorNotificationState } from '../features/PriorNotification/slice' @@ -56,7 +56,7 @@ const commonReducerList = { [monitorfishLightApi.reducerPath]: monitorfishLightApi.reducer, gear: gearReducer, - global: globalSliceReducer, + mainWindow: mainWindowSliceReducer, map: mapReducer, regulatory: regulatoryReducer, species: speciesReducer diff --git a/frontend/src/ui/NoRsuiteOverrideWrapper.tsx b/frontend/src/ui/NoRsuiteOverrideWrapper.tsx index 2848ab9e23..7e19d768e6 100644 --- a/frontend/src/ui/NoRsuiteOverrideWrapper.tsx +++ b/frontend/src/ui/NoRsuiteOverrideWrapper.tsx @@ -28,6 +28,10 @@ import styled from 'styled-components' export const NoRsuiteOverrideWrapper = styled.div` box-sizing: border-box; + * { + box-sizing: border-box; + } + .Field-Checkbox * { line-height: 18px; } From 90a6234480e2537a8d03a268a333170bf6b2a858 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 9 May 2024 10:16:12 +0200 Subject: [PATCH 02/16] Replace soft error logs by assertions in reporting use cases & favorite vessel callback --- .../src/features/Reporting/useCases/addReporting.ts | 12 ++---------- .../features/Reporting/useCases/deleteReporting.ts | 12 ++---------- .../VesselSidebar/VesselSidebarHeader/VesselName.tsx | 12 ++---------- 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/frontend/src/features/Reporting/useCases/addReporting.ts b/frontend/src/features/Reporting/useCases/addReporting.ts index b94b46f8cc..8fde9883e1 100644 --- a/frontend/src/features/Reporting/useCases/addReporting.ts +++ b/frontend/src/features/Reporting/useCases/addReporting.ts @@ -1,7 +1,7 @@ import { addReportingFromAPI } from '@api/reporting' import { getVesselReportings } from '@features/Reporting/useCases/getVesselReportings' import { DisplayedErrorKey } from '@libs/DisplayedError/constants' -import { logSoftError } from '@mtes-mct/monitor-ui' +import { assertNotNullish } from '@utils/assertNotNullish' import { Vessel } from '../../../domain/entities/vessel/vessel' import { addVesselReporting } from '../../../domain/shared_slices/Vessel' @@ -15,15 +15,7 @@ export const addReporting = (newReporting: ReportingCreation): MainAppThunk => async (dispatch, getState) => { const { selectedVesselIdentity } = getState().vessel - // TODO Can this case happen? Is it the right way to handle it? - if (!selectedVesselIdentity) { - logSoftError({ - message: '`selectedVesselIdentity` is null.', - userMessage: 'Aucun navire sélectionné pour ajouter un signalement.' - }) - - return - } + assertNotNullish(selectedVesselIdentity) try { const reporting = await addReportingFromAPI(newReporting) diff --git a/frontend/src/features/Reporting/useCases/deleteReporting.ts b/frontend/src/features/Reporting/useCases/deleteReporting.ts index 756406283e..c1062a1907 100644 --- a/frontend/src/features/Reporting/useCases/deleteReporting.ts +++ b/frontend/src/features/Reporting/useCases/deleteReporting.ts @@ -2,7 +2,7 @@ import { deleteReportingFromAPI } from '@api/reporting' import { ReportingType } from '@features/Reporting/types' import { getVesselReportings } from '@features/Reporting/useCases/getVesselReportings' import { DisplayedErrorKey } from '@libs/DisplayedError/constants' -import { logSoftError } from '@mtes-mct/monitor-ui' +import { assertNotNullish } from '@utils/assertNotNullish' import { Vessel } from '../../../domain/entities/vessel/vessel' import { removeVesselReporting } from '../../../domain/shared_slices/Vessel' @@ -15,15 +15,7 @@ export const deleteReporting = (id: number, reportingType: ReportingType): MainAppThunk => async (dispatch, getState) => { const { selectedVesselIdentity } = getState().vessel - // TODO Can this case happen? Is it the right way to handle it? - if (!selectedVesselIdentity) { - logSoftError({ - message: '`selectedVesselIdentity` is null.', - userMessage: 'Aucun navire sélectionné pour supprimer un signalement.' - }) - - return - } + assertNotNullish(selectedVesselIdentity) try { await deleteReportingFromAPI(id) diff --git a/frontend/src/features/VesselSidebar/VesselSidebarHeader/VesselName.tsx b/frontend/src/features/VesselSidebar/VesselSidebarHeader/VesselName.tsx index af013bb8ee..5e681f3a4b 100644 --- a/frontend/src/features/VesselSidebar/VesselSidebarHeader/VesselName.tsx +++ b/frontend/src/features/VesselSidebar/VesselSidebarHeader/VesselName.tsx @@ -1,4 +1,4 @@ -import { logSoftError } from '@mtes-mct/monitor-ui' +import { assertNotNullish } from '@utils/assertNotNullish' import countries from 'i18n-iso-countries' import { useCallback, useMemo } from 'react' import styled from 'styled-components' @@ -30,15 +30,7 @@ export function VesselName({ focusOnVesselSearchInput }) { const addOrRemoveToFavorites = useCallback( e => { e.stopPropagation() - // TODO Can this case happen? Is it the right way to handle it? - if (!selectedVesselIdentity) { - logSoftError({ - message: '`selectedVesselIdentity` is null.', - userMessage: 'Aucun navire sélectionné à ajouter ou supprimer des favoris.' - }) - - return - } + assertNotNullish(selectedVesselIdentity) if (isFavorite) { dispatch(removeVesselFromFavorites(getVesselCompositeIdentifier(selectedVesselIdentity))) From b7757e0949eea07f4c061df6ee821d2df0a6e3a7 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 9 May 2024 10:19:47 +0200 Subject: [PATCH 03/16] Rename leftDialog to openedLeftDialog in MainWindowState --- .../src/features/MainWindow/components/LeftMenu.tsx | 6 +++--- frontend/src/features/MainWindow/index.tsx | 4 ++-- frontend/src/features/MainWindow/slice.ts | 10 +++++----- .../features/Mission/components/MissionMenuDialog.tsx | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/frontend/src/features/MainWindow/components/LeftMenu.tsx b/frontend/src/features/MainWindow/components/LeftMenu.tsx index 643b921e75..33dfdc2811 100644 --- a/frontend/src/features/MainWindow/components/LeftMenu.tsx +++ b/frontend/src/features/MainWindow/components/LeftMenu.tsx @@ -17,7 +17,7 @@ export function LeftMenu() { const dispatch = useMainAppDispatch() const { favorites } = useMainAppSelector(state => state.favoriteVessel) - const leftDialog = useMainAppSelector(state => state.mainWindow.leftDialog) + const openedLeftDialog = useMainAppSelector(state => state.mainWindow.openedLeftDialog) const isAlertsMapButtonDisplayed = useMainAppSelector(state => state.displayedComponent.isAlertsMapButtonDisplayed) const isBeaconMalfunctionsMapButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isBeaconMalfunctionsMapButtonDisplayed @@ -65,7 +65,7 @@ export function LeftMenu() { {isFavoriteVesselsMapButtonDisplayed && ( - + {favorites?.length || 0} @@ -78,7 +78,7 @@ export function LeftMenu() { state.displayedComponent.isVesselSearchDisplayed) const isVesselSidebarOpen = useMainAppSelector(state => state.vessel.vesselSidebarIsOpen) const isDraftDirty = useMainAppSelector(state => state.missionForm.isDraftDirty) - const leftDialog = useMainAppSelector(state => state.mainWindow.leftDialog) + const openedLeftDialog = useMainAppSelector(state => state.mainWindow.openedLeftDialog) const status = useMainAppSelector(state => state.sideWindow.status) const warnOnUnload = useCallback( @@ -88,7 +88,7 @@ export function MainWindow() { {isDrawLayerModalDisplayed && } - {leftDialog?.key === MapBox.MISSIONS && } + {openedLeftDialog?.key === MapBox.MISSIONS && } ) } diff --git a/frontend/src/features/MainWindow/slice.ts b/frontend/src/features/MainWindow/slice.ts index 61480a19ec..0ea470f7d7 100644 --- a/frontend/src/features/MainWindow/slice.ts +++ b/frontend/src/features/MainWindow/slice.ts @@ -19,13 +19,13 @@ export type MainWindowState = { isBackoffice: boolean isUpdatingVessels: boolean lastSearchedVessels: any[] - leftDialog: + leftMapBoxOpened: MapBox | undefined + openedLeftDialog: | { key: MapBox topPosition: number } | undefined - leftMapBoxOpened: MapBox | undefined // TODO Rename this prop. // TODO Investigate that. Should be a defined boolean. previewFilteredVesselsMode: boolean | undefined @@ -41,8 +41,8 @@ const INITIAL_STATE: MainWindowState = { isBackoffice: false, isUpdatingVessels: false, lastSearchedVessels: getLocalStorageState([], lastSearchedVesselsLocalStorageKey), - leftDialog: undefined, leftMapBoxOpened: undefined, + openedLeftDialog: undefined, previewFilteredVesselsMode: undefined, rightMapBoxOpened: undefined, rightMenuIsOpen: false, @@ -82,7 +82,7 @@ export const mainWindowSlice = createSlice({ * Close the left dialog. */ closeLeftDialog(state) { - state.leftDialog = undefined + state.openedLeftDialog = undefined }, closeVesselListModal(state) { @@ -185,7 +185,7 @@ export const mainWindowSlice = createSlice({ topPosition: number }> ) { - state.leftDialog = action.payload.key === state.leftDialog?.key ? undefined : action.payload + state.openedLeftDialog = action.payload.key === state.openedLeftDialog?.key ? undefined : action.payload } } }) diff --git a/frontend/src/features/Mission/components/MissionMenuDialog.tsx b/frontend/src/features/Mission/components/MissionMenuDialog.tsx index fd563b083c..19569f6381 100644 --- a/frontend/src/features/Mission/components/MissionMenuDialog.tsx +++ b/frontend/src/features/Mission/components/MissionMenuDialog.tsx @@ -16,8 +16,8 @@ export function MissionMenuDialog() { const dispatch = useMainAppDispatch() const sideWindow = useMainAppSelector(state => state.sideWindow) const isMissionsLayerDisplayed = useMainAppSelector(state => state.displayedComponent.isMissionsLayerDisplayed) - const leftDialog = useMainAppSelector(state => state.mainWindow.leftDialog) - assertNotNullish(leftDialog) + const openedLeftDialog = useMainAppSelector(state => state.mainWindow.openedLeftDialog) + assertNotNullish(openedLeftDialog) const isActive = sideWindow.status !== SideWindowStatus.CLOSED && sideWindow.selectedPath.menu === SideWindowMenuKey.MISSION_LIST @@ -45,7 +45,7 @@ export function MissionMenuDialog() { } return ( - + Missions et contrôles From 863339b66cc2f4777f393aaa61ace83cf4adda05 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 9 May 2024 11:07:30 +0200 Subject: [PATCH 04/16] Add isPriorNotificationsLeftMenuButtonDisplayed prop to DisplayedComponentState --- .../shared_slices/DisplayedComponent.ts | 41 ++++++++-------- .../vessel/addVesselListFilterZone.ts | 10 ++-- .../MainWindow/components/LeftMenu.tsx | 34 +++++++------ .../MapButtons/FavoriteVessels/index.tsx | 2 +- .../components/MapButtons/index.tsx | 48 +++++++++---------- .../Mission/useCases/addOrEditMissionZone.ts | 40 ++++++++-------- 6 files changed, 90 insertions(+), 85 deletions(-) diff --git a/frontend/src/domain/shared_slices/DisplayedComponent.ts b/frontend/src/domain/shared_slices/DisplayedComponent.ts index 993991debd..1873ecb736 100644 --- a/frontend/src/domain/shared_slices/DisplayedComponent.ts +++ b/frontend/src/domain/shared_slices/DisplayedComponent.ts @@ -7,55 +7,56 @@ import type { PayloadAction } from '@reduxjs/toolkit' const displayedComponentsLocalstorageKey = 'displayedComponents' +// TODO Move this slice either into `MainWindow` slice, or create related feature components slices (LeftMenu, RightMenu, etc.). export type DisplayedComponentState = { areVesselsDisplayed: boolean isAccountMapButtonDisplayed: boolean - isAlertsMapButtonDisplayed: boolean - isBeaconMalfunctionsMapButtonDisplayed: boolean + isAlertsLeftMenuButtonDisplayed: boolean + isBeaconMalfunctionsLeftMenuButtonDisplayed: boolean isControlUnitDialogDisplayed: boolean isControlUnitListDialogDisplayed: boolean isControlUnitListMapButtonDisplayed: boolean isDrawLayerModalDisplayed: boolean - isFavoriteVesselsMapButtonDisplayed: boolean - isInterestPointMapButtonDisplayed: boolean - isMeasurementMapButtonDisplayed: boolean + isFavoriteVesselsLeftMenuButtonDisplayed: boolean + isInterestPointRightMenuButtonDisplayed: boolean + isMeasurementRightMenuButtonDisplayed: boolean isMissionsLayerDisplayed: boolean - isMissionsMapButtonDisplayed: boolean - isPriorNotificationMapButtonDisplayed: boolean + isMissionsLeftMenuButtonDisplayed: boolean + isPriorNotificationLeftMenuButtonDisplayed: boolean isStationLayerDisplayed: boolean - isVesselFiltersMapButtonDisplayed: boolean - isVesselLabelsMapButtonDisplayed: boolean + isVesselFiltersRightMenuButtonDisplayed: boolean + isVesselLabelsRightMenuButtonDisplayed: boolean isVesselListDisplayed: boolean isVesselListModalDisplayed: boolean isVesselSearchDisplayed: boolean - isVesselVisibilityMapButtonDisplayed: boolean + isVesselVisibilityRightMenuButtonDisplayed: boolean } const INITIAL_STATE: DisplayedComponentState = { areVesselsDisplayed: true, isAccountMapButtonDisplayed: true, - isAlertsMapButtonDisplayed: true, - isBeaconMalfunctionsMapButtonDisplayed: true, + isAlertsLeftMenuButtonDisplayed: true, + isBeaconMalfunctionsLeftMenuButtonDisplayed: true, isControlUnitDialogDisplayed: false, isControlUnitListDialogDisplayed: false, isControlUnitListMapButtonDisplayed: true, isDrawLayerModalDisplayed: false, - isFavoriteVesselsMapButtonDisplayed: true, - isInterestPointMapButtonDisplayed: true, - isMeasurementMapButtonDisplayed: true, + isFavoriteVesselsLeftMenuButtonDisplayed: true, + isInterestPointRightMenuButtonDisplayed: true, + isMeasurementRightMenuButtonDisplayed: true, isMissionsLayerDisplayed: getLocalstorageProperty( true, displayedComponentsLocalstorageKey, 'isMissionsLayerDisplayed' ), - isMissionsMapButtonDisplayed: true, - isPriorNotificationMapButtonDisplayed: true, + isMissionsLeftMenuButtonDisplayed: true, + isPriorNotificationLeftMenuButtonDisplayed: true, isStationLayerDisplayed: false, - isVesselFiltersMapButtonDisplayed: true, - isVesselLabelsMapButtonDisplayed: true, + isVesselFiltersRightMenuButtonDisplayed: true, + isVesselLabelsRightMenuButtonDisplayed: true, isVesselListDisplayed: true, isVesselListModalDisplayed: false, isVesselSearchDisplayed: true, - isVesselVisibilityMapButtonDisplayed: true + isVesselVisibilityRightMenuButtonDisplayed: true } /** diff --git a/frontend/src/domain/use_cases/vessel/addVesselListFilterZone.ts b/frontend/src/domain/use_cases/vessel/addVesselListFilterZone.ts index a641139cf5..bd99311284 100644 --- a/frontend/src/domain/use_cases/vessel/addVesselListFilterZone.ts +++ b/frontend/src/domain/use_cases/vessel/addVesselListFilterZone.ts @@ -21,13 +21,13 @@ export const closeDrawLayerModal = dispatch => { dispatch( setDisplayedComponents({ isDrawLayerModalDisplayed: false, - isInterestPointMapButtonDisplayed: true, - isMeasurementMapButtonDisplayed: true, - isVesselFiltersMapButtonDisplayed: true, - isVesselLabelsMapButtonDisplayed: true, + isInterestPointRightMenuButtonDisplayed: true, + isMeasurementRightMenuButtonDisplayed: true, + isVesselFiltersRightMenuButtonDisplayed: true, + isVesselLabelsRightMenuButtonDisplayed: true, isVesselListDisplayed: true, isVesselSearchDisplayed: true, - isVesselVisibilityMapButtonDisplayed: true + isVesselVisibilityRightMenuButtonDisplayed: true }) ) } diff --git a/frontend/src/features/MainWindow/components/LeftMenu.tsx b/frontend/src/features/MainWindow/components/LeftMenu.tsx index 33dfdc2811..d51c9d7add 100644 --- a/frontend/src/features/MainWindow/components/LeftMenu.tsx +++ b/frontend/src/features/MainWindow/components/LeftMenu.tsx @@ -16,17 +16,22 @@ export function LeftMenu() { const missionButtonRef = useRef(null) const dispatch = useMainAppDispatch() - const { favorites } = useMainAppSelector(state => state.favoriteVessel) + const favorites = useMainAppSelector(state => state.favoriteVessel.favorites) const openedLeftDialog = useMainAppSelector(state => state.mainWindow.openedLeftDialog) - const isAlertsMapButtonDisplayed = useMainAppSelector(state => state.displayedComponent.isAlertsMapButtonDisplayed) - const isBeaconMalfunctionsMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isBeaconMalfunctionsMapButtonDisplayed + const isAlertsLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isAlertsLeftMenuButtonDisplayed ) - const isFavoriteVesselsMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isFavoriteVesselsMapButtonDisplayed + const isBeaconMalfunctionsLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isBeaconMalfunctionsLeftMenuButtonDisplayed ) - const isMissionsMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isMissionsMapButtonDisplayed + const isFavoriteVesselsLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isFavoriteVesselsLeftMenuButtonDisplayed + ) + const isMissionsLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isMissionsLeftMenuButtonDisplayed + ) + const isPriorNotificationLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isPriorNotificationLeftMenuButtonDisplayed ) const isSuperUser = useIsSuperUser() // const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) @@ -62,7 +67,7 @@ export function LeftMenu() { - {isFavoriteVesselsMapButtonDisplayed && ( + {isFavoriteVesselsLeftMenuButtonDisplayed && ( @@ -74,7 +79,7 @@ export function LeftMenu() { )} - {isSuperUser && isMissionsMapButtonDisplayed && ( + {isSuperUser && isMissionsLeftMenuButtonDisplayed && ( )} - {isSuperUser && isAlertsMapButtonDisplayed && ( + {isSuperUser && isAlertsLeftMenuButtonDisplayed && ( )} - {import.meta.env.FRONTEND_PRIOR_NOTIFICATION_LIST_ENABLED === 'true' && ( - - )} + {import.meta.env.FRONTEND_PRIOR_NOTIFICATION_LIST_ENABLED === 'true' && + isPriorNotificationLeftMenuButtonDisplayed && } - {isSuperUser && isBeaconMalfunctionsMapButtonDisplayed && } + {isSuperUser && isBeaconMalfunctionsLeftMenuButtonDisplayed && } ) diff --git a/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx b/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx index 013d92d7e6..7fe15a39a8 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx @@ -18,7 +18,7 @@ import { MapButton } from '../MapButton' export function FavoriteVessels() { const dispatch = useMainAppDispatch() - const { favorites } = useMainAppSelector(state => state.favoriteVessel) + const favorites = useMainAppSelector(state => state.favoriteVessel.favorites) const { hideNonSelectedVessels, selectedVesselIdentity, vesselsTracksShowed } = useMainAppSelector( state => state.vessel ) diff --git a/frontend/src/features/MainWindow/components/MapButtons/index.tsx b/frontend/src/features/MainWindow/components/MapButtons/index.tsx index c513bdc972..7f43d325ae 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/index.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/index.tsx @@ -16,47 +16,47 @@ import { PriorNotificationListButton } from '../../../PriorNotification/componen export function MapButtons() { const isSuperUser = useIsSuperUser() const isAccountMapButtonDisplayed = useMainAppSelector(state => state.displayedComponent.isAccountMapButtonDisplayed) - const isPriorNotificationMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isPriorNotificationMapButtonDisplayed + const isBeaconMalfunctionsLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isBeaconMalfunctionsLeftMenuButtonDisplayed ) const isControlUnitListMapButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isControlUnitListMapButtonDisplayed ) - const isBeaconMalfunctionsMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isBeaconMalfunctionsMapButtonDisplayed + const isFavoriteVesselsLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isFavoriteVesselsLeftMenuButtonDisplayed ) - const isFavoriteVesselsMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isFavoriteVesselsMapButtonDisplayed + const isInterestPointRightMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isInterestPointRightMenuButtonDisplayed ) - const isInterestPointMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isInterestPointMapButtonDisplayed + const isMeasurementRightMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isMeasurementRightMenuButtonDisplayed ) - const isMeasurementMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isMeasurementMapButtonDisplayed + const isPriorNotificationLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isPriorNotificationLeftMenuButtonDisplayed ) - const isVesselFiltersMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isVesselFiltersMapButtonDisplayed + const isVesselFiltersRightMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isVesselFiltersRightMenuButtonDisplayed ) - const isVesselLabelsMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isVesselLabelsMapButtonDisplayed + const isVesselLabelsRightMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isVesselLabelsRightMenuButtonDisplayed ) - const isVesselVisibilityMapButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isVesselVisibilityMapButtonDisplayed + const isVesselVisibilityRightMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isVesselVisibilityRightMenuButtonDisplayed ) return ( <> - {isFavoriteVesselsMapButtonDisplayed && } + {isFavoriteVesselsLeftMenuButtonDisplayed && } {(isSuperUser || import.meta.env.FRONTEND_PRIOR_NOTIFICATION_LIST_ENABLED === 'true') && - isPriorNotificationMapButtonDisplayed && } - {isSuperUser && isBeaconMalfunctionsMapButtonDisplayed && } + isPriorNotificationLeftMenuButtonDisplayed && } + {isSuperUser && isBeaconMalfunctionsLeftMenuButtonDisplayed && } - {isVesselFiltersMapButtonDisplayed && } - {isVesselVisibilityMapButtonDisplayed && } - {isMeasurementMapButtonDisplayed && } - {isInterestPointMapButtonDisplayed && } - {isVesselLabelsMapButtonDisplayed && } + {isVesselFiltersRightMenuButtonDisplayed && } + {isVesselVisibilityRightMenuButtonDisplayed && } + {isMeasurementRightMenuButtonDisplayed && } + {isInterestPointRightMenuButtonDisplayed && } + {isVesselLabelsRightMenuButtonDisplayed && } {isAccountMapButtonDisplayed && } diff --git a/frontend/src/features/Mission/useCases/addOrEditMissionZone.ts b/frontend/src/features/Mission/useCases/addOrEditMissionZone.ts index a943af2b44..78e98815d8 100644 --- a/frontend/src/features/Mission/useCases/addOrEditMissionZone.ts +++ b/frontend/src/features/Mission/useCases/addOrEditMissionZone.ts @@ -31,21 +31,21 @@ export const openDrawLayerModal = dispatch => { setDisplayedComponents({ areVesselsDisplayed: false, isAccountMapButtonDisplayed: false, - isAlertsMapButtonDisplayed: false, - isBeaconMalfunctionsMapButtonDisplayed: false, + isAlertsLeftMenuButtonDisplayed: false, + isBeaconMalfunctionsLeftMenuButtonDisplayed: false, isControlUnitListMapButtonDisplayed: false, isDrawLayerModalDisplayed: true, - isFavoriteVesselsMapButtonDisplayed: false, - isInterestPointMapButtonDisplayed: false, - isMeasurementMapButtonDisplayed: false, + isFavoriteVesselsLeftMenuButtonDisplayed: false, + isInterestPointRightMenuButtonDisplayed: false, + isMeasurementRightMenuButtonDisplayed: false, isMissionsLayerDisplayed: false, - isMissionsMapButtonDisplayed: false, - isPriorNotificationMapButtonDisplayed: false, - isVesselFiltersMapButtonDisplayed: false, - isVesselLabelsMapButtonDisplayed: false, + isMissionsLeftMenuButtonDisplayed: false, + isPriorNotificationLeftMenuButtonDisplayed: false, + isVesselFiltersRightMenuButtonDisplayed: false, + isVesselLabelsRightMenuButtonDisplayed: false, isVesselListDisplayed: false, isVesselSearchDisplayed: false, - isVesselVisibilityMapButtonDisplayed: false + isVesselVisibilityRightMenuButtonDisplayed: false }) ) } @@ -55,21 +55,21 @@ export const closeDrawLayerModal = dispatch => { setDisplayedComponents({ areVesselsDisplayed: true, isAccountMapButtonDisplayed: true, - isAlertsMapButtonDisplayed: true, - isBeaconMalfunctionsMapButtonDisplayed: true, + isAlertsLeftMenuButtonDisplayed: true, + isBeaconMalfunctionsLeftMenuButtonDisplayed: true, isControlUnitListMapButtonDisplayed: true, isDrawLayerModalDisplayed: false, - isFavoriteVesselsMapButtonDisplayed: true, - isInterestPointMapButtonDisplayed: true, - isMeasurementMapButtonDisplayed: true, + isFavoriteVesselsLeftMenuButtonDisplayed: true, + isInterestPointRightMenuButtonDisplayed: true, + isMeasurementRightMenuButtonDisplayed: true, isMissionsLayerDisplayed: true, - isMissionsMapButtonDisplayed: true, - isPriorNotificationMapButtonDisplayed: true, - isVesselFiltersMapButtonDisplayed: true, - isVesselLabelsMapButtonDisplayed: true, + isMissionsLeftMenuButtonDisplayed: true, + isPriorNotificationLeftMenuButtonDisplayed: true, + isVesselFiltersRightMenuButtonDisplayed: true, + isVesselLabelsRightMenuButtonDisplayed: true, isVesselListDisplayed: true, isVesselSearchDisplayed: true, - isVesselVisibilityMapButtonDisplayed: true + isVesselVisibilityRightMenuButtonDisplayed: true }) ) } From 1139f3dfd4c7dd6137be40f77d2c72090204be9e Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Mon, 13 May 2024 04:54:01 +0200 Subject: [PATCH 05/16] Add restorable main window components display state --- .../shared_slices/DisplayedComponent.ts | 8 +++- frontend/src/features/MainWindow/slice.ts | 13 +++++ ...MainWindowComponentsAndSaveDisplayState.ts | 13 +++++ .../useCases/restoreMainWindowDisplayState.ts | 10 ++++ .../Mission/useCases/addOrEditMissionZone.ts | 48 ++----------------- 5 files changed, 48 insertions(+), 44 deletions(-) create mode 100644 frontend/src/features/MainWindow/useCases/hideAllMainWindowComponentsAndSaveDisplayState.ts create mode 100644 frontend/src/features/MainWindow/useCases/restoreMainWindowDisplayState.ts diff --git a/frontend/src/domain/shared_slices/DisplayedComponent.ts b/frontend/src/domain/shared_slices/DisplayedComponent.ts index 1873ecb736..5b04f45d83 100644 --- a/frontend/src/domain/shared_slices/DisplayedComponent.ts +++ b/frontend/src/domain/shared_slices/DisplayedComponent.ts @@ -31,7 +31,7 @@ export type DisplayedComponentState = { isVesselSearchDisplayed: boolean isVesselVisibilityRightMenuButtonDisplayed: boolean } -const INITIAL_STATE: DisplayedComponentState = { +export const INITIAL_STATE: DisplayedComponentState = { areVesselsDisplayed: true, isAccountMapButtonDisplayed: true, isAlertsLeftMenuButtonDisplayed: true, @@ -68,6 +68,12 @@ const displayedComponentSlice = createSlice({ initialState: INITIAL_STATE, name: 'displayedComponent', reducers: { + hideAll(state) { + Object.keys(INITIAL_STATE).forEach(propertyKey => { + state[propertyKey] = false + }) + }, + setDisplayedComponents(state, action: PayloadAction>) { Object.keys(INITIAL_STATE).forEach(propertyKey => { const value = getValueOrDefault(action.payload[propertyKey], state[propertyKey]) diff --git a/frontend/src/features/MainWindow/slice.ts b/frontend/src/features/MainWindow/slice.ts index 0ea470f7d7..4f10d574ac 100644 --- a/frontend/src/features/MainWindow/slice.ts +++ b/frontend/src/features/MainWindow/slice.ts @@ -1,4 +1,8 @@ import { createSlice } from '@reduxjs/toolkit' +import { + type DisplayedComponentState, + INITIAL_STATE as DISPLAYED_COMPONENT_INITIAL_STATE +} from 'domain/shared_slices/DisplayedComponent' import { UserType } from '../../domain/entities/beaconMalfunction/constants' import { getOnlyVesselIdentityProperties, vesselsAreEquals } from '../../domain/entities/vessel/vessel' @@ -18,6 +22,7 @@ export type MainWindowState = { healthcheckTextWarning: string[] isBackoffice: boolean isUpdatingVessels: boolean + lastDisplayState: DisplayedComponentState lastSearchedVessels: any[] leftMapBoxOpened: MapBox | undefined openedLeftDialog: @@ -40,6 +45,7 @@ const INITIAL_STATE: MainWindowState = { healthcheckTextWarning: [], isBackoffice: false, isUpdatingVessels: false, + lastDisplayState: DISPLAYED_COMPONENT_INITIAL_STATE, lastSearchedVessels: getLocalStorageState([], lastSearchedVesselsLocalStorageKey), leftMapBoxOpened: undefined, openedLeftDialog: undefined, @@ -144,6 +150,13 @@ export const mainWindowSlice = createSlice({ state.isUpdatingVessels = true }, + /** + * @internal Don't use this action directly. Use `hideAllMainWindowComponentsAndSaveDisplayState` dispatcher. + */ + setLastDisplayState(state, action: PayloadAction) { + state.lastDisplayState = action.payload + }, + /** * Set the left box, so the other boxes can close */ diff --git a/frontend/src/features/MainWindow/useCases/hideAllMainWindowComponentsAndSaveDisplayState.ts b/frontend/src/features/MainWindow/useCases/hideAllMainWindowComponentsAndSaveDisplayState.ts new file mode 100644 index 0000000000..1d2e15d1e0 --- /dev/null +++ b/frontend/src/features/MainWindow/useCases/hideAllMainWindowComponentsAndSaveDisplayState.ts @@ -0,0 +1,13 @@ +import { displayedComponentActions } from 'domain/shared_slices/DisplayedComponent' + +import { mainWindowActions } from '../slice' + +import type { MainAppThunk } from '@store' + +// TODO We won't need this intermediate dispatcher once `DisplayedComponent` slice is merged into `MainWindow` slice. +export const hideAllMainWindowComponentsAndSaveDisplayState = (): MainAppThunk => (dispatch, getState) => { + const { displayedComponent } = getState() + + dispatch(mainWindowActions.setLastDisplayState(displayedComponent)) + dispatch(displayedComponentActions.hideAll()) +} diff --git a/frontend/src/features/MainWindow/useCases/restoreMainWindowDisplayState.ts b/frontend/src/features/MainWindow/useCases/restoreMainWindowDisplayState.ts new file mode 100644 index 0000000000..a90b8b4165 --- /dev/null +++ b/frontend/src/features/MainWindow/useCases/restoreMainWindowDisplayState.ts @@ -0,0 +1,10 @@ +import { displayedComponentActions } from 'domain/shared_slices/DisplayedComponent' + +import type { MainAppThunk } from '@store' + +// TODO We won't need this intermediate dispatcher once `DisplayedComponent` slice is merged into `MainWindow` slice. +export const restoreMainWindowDisplayState = (): MainAppThunk => (dispatch, getState) => { + const { mainWindow } = getState() + + dispatch(displayedComponentActions.setDisplayedComponents(mainWindow.lastDisplayState)) +} diff --git a/frontend/src/features/Mission/useCases/addOrEditMissionZone.ts b/frontend/src/features/Mission/useCases/addOrEditMissionZone.ts index 78e98815d8..872685bed1 100644 --- a/frontend/src/features/Mission/useCases/addOrEditMissionZone.ts +++ b/frontend/src/features/Mission/useCases/addOrEditMissionZone.ts @@ -1,5 +1,7 @@ +import { hideAllMainWindowComponentsAndSaveDisplayState } from '@features/MainWindow/useCases/hideAllMainWindowComponentsAndSaveDisplayState' +import { restoreMainWindowDisplayState } from '@features/MainWindow/useCases/restoreMainWindowDisplayState' + import { InteractionListener, InteractionType } from '../../../domain/entities/map/constants' -import { setDisplayedComponents } from '../../../domain/shared_slices/DisplayedComponent' import { fitMultiPolygonToExtent } from '../../../domain/use_cases/map/fitMultiPolygonToExtent' import { unselectVessel } from '../../../domain/use_cases/vessel/unselectVessel' import { setInitialGeometry, setInteractionTypeAndListener } from '../../Draw/slice' @@ -27,49 +29,9 @@ export const addOrEditMissionZone = } export const openDrawLayerModal = dispatch => { - dispatch( - setDisplayedComponents({ - areVesselsDisplayed: false, - isAccountMapButtonDisplayed: false, - isAlertsLeftMenuButtonDisplayed: false, - isBeaconMalfunctionsLeftMenuButtonDisplayed: false, - isControlUnitListMapButtonDisplayed: false, - isDrawLayerModalDisplayed: true, - isFavoriteVesselsLeftMenuButtonDisplayed: false, - isInterestPointRightMenuButtonDisplayed: false, - isMeasurementRightMenuButtonDisplayed: false, - isMissionsLayerDisplayed: false, - isMissionsLeftMenuButtonDisplayed: false, - isPriorNotificationLeftMenuButtonDisplayed: false, - isVesselFiltersRightMenuButtonDisplayed: false, - isVesselLabelsRightMenuButtonDisplayed: false, - isVesselListDisplayed: false, - isVesselSearchDisplayed: false, - isVesselVisibilityRightMenuButtonDisplayed: false - }) - ) + dispatch(hideAllMainWindowComponentsAndSaveDisplayState()) } export const closeDrawLayerModal = dispatch => { - dispatch( - setDisplayedComponents({ - areVesselsDisplayed: true, - isAccountMapButtonDisplayed: true, - isAlertsLeftMenuButtonDisplayed: true, - isBeaconMalfunctionsLeftMenuButtonDisplayed: true, - isControlUnitListMapButtonDisplayed: true, - isDrawLayerModalDisplayed: false, - isFavoriteVesselsLeftMenuButtonDisplayed: true, - isInterestPointRightMenuButtonDisplayed: true, - isMeasurementRightMenuButtonDisplayed: true, - isMissionsLayerDisplayed: true, - isMissionsLeftMenuButtonDisplayed: true, - isPriorNotificationLeftMenuButtonDisplayed: true, - isVesselFiltersRightMenuButtonDisplayed: true, - isVesselLabelsRightMenuButtonDisplayed: true, - isVesselListDisplayed: true, - isVesselSearchDisplayed: true, - isVesselVisibilityRightMenuButtonDisplayed: true - }) - ) + dispatch(restoreMainWindowDisplayState()) } From 916b13812eeafe02b2cc0e6e837a8ed1a4e0354e Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Mon, 13 May 2024 05:08:02 +0200 Subject: [PATCH 06/16] Simplify MapComponents component --- .../VesselSidebarHeader/index.tsx | 2 +- .../features/commonStyles/MapComponent.tsx | 22 +------------------ 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/frontend/src/features/VesselSidebar/VesselSidebarHeader/index.tsx b/frontend/src/features/VesselSidebar/VesselSidebarHeader/index.tsx index 95036140b3..1250f92327 100644 --- a/frontend/src/features/VesselSidebar/VesselSidebarHeader/index.tsx +++ b/frontend/src/features/VesselSidebar/VesselSidebarHeader/index.tsx @@ -45,9 +45,9 @@ export function VesselSidebarHeader() { return ( <> {isVesselNameShown && ( dispatch(setIsFocusedOnVesselSearch(true))} /> diff --git a/frontend/src/features/commonStyles/MapComponent.tsx b/frontend/src/features/commonStyles/MapComponent.tsx index 851ea4334f..7c2b5b4e7f 100644 --- a/frontend/src/features/commonStyles/MapComponent.tsx +++ b/frontend/src/features/commonStyles/MapComponent.tsx @@ -1,26 +1,6 @@ import styled from 'styled-components' -import type { ReactNode } from 'react' - -type MapComponentStyleType = { - children: ReactNode - className?: string - isHidden?: boolean | undefined -} -export function MapComponent({ children, className, isHidden, ...props }: MapComponentStyleType) { - return ( - - {children} - - ) -} - -const Wrapper = styled.div<{ +export const MapComponent = styled.div<{ $isHidden?: boolean | undefined }>` visibility: ${p => (p.$isHidden ? 'hidden' : 'visible')}; From c4e9f5dbde6e8a4bcaa1401c6cea4324a7801806 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Mon, 13 May 2024 06:24:09 +0200 Subject: [PATCH 07/16] Use all main window comps hide/restore in filtered vessel list preview --- frontend/src/features/VesselList/index.tsx | 2 ++ ...Vessels.jsx => PreviewFilteredVessels.tsx} | 23 +++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) rename frontend/src/features/preview_filtered_vessels/{PreviewFilteredVessels.jsx => PreviewFilteredVessels.tsx} (56%) diff --git a/frontend/src/features/VesselList/index.tsx b/frontend/src/features/VesselList/index.tsx index 2bdc777516..3b64337181 100644 --- a/frontend/src/features/VesselList/index.tsx +++ b/frontend/src/features/VesselList/index.tsx @@ -1,5 +1,6 @@ import { MapToolButton } from '@features/MainWindow/components/MapButtons/shared/MapToolButton' import { SaveVesselFiltersModal } from '@features/MainWindow/components/MapButtons/VesselFilters/SaveVesselFiltersModal' +import { hideAllMainWindowComponentsAndSaveDisplayState } from '@features/MainWindow/useCases/hideAllMainWindowComponentsAndSaveDisplayState' import { THEME } from '@mtes-mct/monitor-ui' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { batch } from 'react-redux' @@ -285,6 +286,7 @@ export function VesselList({ namespace }) { if (vesselFeatureIds?.length) { dispatch(setPreviewFilteredVesselsFeatures(vesselFeatureIds)) dispatch(setPreviewFilteredVesselsMode(true)) + dispatch(hideAllMainWindowComponentsAndSaveDisplayState()) if (zonesSelected?.length) { // TODO Finish that diff --git a/frontend/src/features/preview_filtered_vessels/PreviewFilteredVessels.jsx b/frontend/src/features/preview_filtered_vessels/PreviewFilteredVessels.tsx similarity index 56% rename from frontend/src/features/preview_filtered_vessels/PreviewFilteredVessels.jsx rename to frontend/src/features/preview_filtered_vessels/PreviewFilteredVessels.tsx index 195a124a96..4d3233cb10 100644 --- a/frontend/src/features/preview_filtered_vessels/PreviewFilteredVessels.jsx +++ b/frontend/src/features/preview_filtered_vessels/PreviewFilteredVessels.tsx @@ -1,15 +1,15 @@ -import React from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { setPreviewFilteredVesselsMode } from '@features/MainWindow/slice' +import { restoreMainWindowDisplayState } from '@features/MainWindow/useCases/restoreMainWindowDisplayState' +import { useMainAppDispatch } from '@hooks/useMainAppDispatch' +import { useMainAppSelector } from '@hooks/useMainAppSelector' import styled from 'styled-components' -import { COLORS } from '../../constants/constants' import BackToVesselsListSVG from '../icons/Fleche_navigation_marees_gainsboro.svg?react' -import { setPreviewFilteredVesselsMode } from '../MainWindow/slice' -function PreviewFilteredVessels() { - const dispatch = useDispatch() +export function PreviewFilteredVessels() { + const dispatch = useMainAppDispatch() - const { previewFilteredVesselsMode } = useSelector(state => state.mainWindow) + const { previewFilteredVesselsMode } = useMainAppSelector(state => state.mainWindow) return ( <> @@ -18,6 +18,7 @@ function PreviewFilteredVessels() { data-cy="back-to-vessels-list" onClick={() => { dispatch(setPreviewFilteredVesselsMode(false)) + dispatch(restoreMainWindowDisplayState()) }} > @@ -39,17 +40,15 @@ const BackToVesselsList = styled(BackToVesselsListSVG)` const Text = styled.div` font: normal normal normal 22px/31px Marianne; - color: ${COLORS.gainsboro}; + color: ${p => p.theme.color.gainsboro}; ` const Preview = styled.div` - background: ${COLORS.charcoal} 0% 0% no-repeat padding-box; - width 100%; + background: ${p => p.theme.color.charcoal} 0% 0% no-repeat padding-box; + width: 100%; height: 24px; text-align: center; padding: 17px; padding-top: 9px; cursor: pointer; ` - -export default PreviewFilteredVessels From a00305e4c059411647d3e426bbe65eef7a403f68 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Mon, 13 May 2024 06:38:24 +0200 Subject: [PATCH 08/16] Move favorite vessel list dialog to main window left menu --- .../components/ControlUnitListMapButton.tsx | 1 - .../MainWindow/components/LeftMenu.tsx | 105 +++++++--- .../BeaconMalfunctionsMapButton.tsx | 67 ------ .../MapButtons/FavoriteVessels/index.tsx | 190 ------------------ .../components/MapButtons/index.tsx | 17 -- frontend/src/features/MainWindow/index.tsx | 14 +- .../Mission/components/MissionMenuDialog.tsx | 5 +- .../FavoriteVessel.tsx | 13 +- .../FavoriteVesselListDialog/index.tsx | 105 ++++++++++ 9 files changed, 207 insertions(+), 310 deletions(-) delete mode 100644 frontend/src/features/MainWindow/components/MapButtons/BeaconMalfunctionsMapButton.tsx delete mode 100644 frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx rename frontend/src/features/{MainWindow/components/MapButtons/FavoriteVessels => Vessel/components/FavoriteVesselListDialog}/FavoriteVessel.tsx (87%) create mode 100644 frontend/src/features/Vessel/components/FavoriteVesselListDialog/index.tsx diff --git a/frontend/src/features/ControlUnit/components/ControlUnitListMapButton.tsx b/frontend/src/features/ControlUnit/components/ControlUnitListMapButton.tsx index 887171188b..c1613d1371 100644 --- a/frontend/src/features/ControlUnit/components/ControlUnitListMapButton.tsx +++ b/frontend/src/features/ControlUnit/components/ControlUnitListMapButton.tsx @@ -11,7 +11,6 @@ export function ControlUnitListMapButton() { const wrapperRef = useRef(null) const dispatch = useMainAppDispatch() - // const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) const rightMenuIsOpen = useMainAppSelector(state => state.mainWindow.rightMenuIsOpen) const isControlUnitDialogDisplayed = useMainAppSelector( state => state.displayedComponent.isControlUnitDialogDisplayed diff --git a/frontend/src/features/MainWindow/components/LeftMenu.tsx b/frontend/src/features/MainWindow/components/LeftMenu.tsx index d51c9d7add..5c43c147ac 100644 --- a/frontend/src/features/MainWindow/components/LeftMenu.tsx +++ b/frontend/src/features/MainWindow/components/LeftMenu.tsx @@ -2,7 +2,7 @@ import { openSideWindowPath } from '@features/SideWindow/useCases/openSideWindow import { useIsSuperUser } from '@hooks/authorization/useIsSuperUser' import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { useMainAppSelector } from '@hooks/useMainAppSelector' -import { Icon, IconButton, Size } from '@mtes-mct/monitor-ui' +import { Figure, Icon, IconButton, Size } from '@mtes-mct/monitor-ui' import { assertNotNullish } from '@utils/assertNotNullish' import { MapBox } from 'domain/entities/map/constants' import { SideWindowMenuKey, SideWindowStatus } from 'domain/entities/sideWindow/constants' @@ -13,11 +13,15 @@ import styled from 'styled-components' import { mainWindowActions } from '../slice' export function LeftMenu() { - const missionButtonRef = useRef(null) + const favoriteVesselsButtonRef = useRef(null) + const missionsButtonRef = useRef(null) const dispatch = useMainAppDispatch() const favorites = useMainAppSelector(state => state.favoriteVessel.favorites) + const isSuperUser = useIsSuperUser() const openedLeftDialog = useMainAppSelector(state => state.mainWindow.openedLeftDialog) + const sideWindow = useMainAppSelector(state => state.sideWindow) + const isAlertsLeftMenuButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isAlertsLeftMenuButtonDisplayed ) @@ -33,26 +37,45 @@ export function LeftMenu() { const isPriorNotificationLeftMenuButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isPriorNotificationLeftMenuButtonDisplayed ) - const isSuperUser = useIsSuperUser() - // const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) - const sideWindow = useMainAppSelector(state => state.sideWindow) + + const isSideWindowAlertsActive = + sideWindow.status !== SideWindowStatus.CLOSED && + sideWindow.selectedPath.menu === SideWindowMenuKey.ALERT_LIST_AND_REPORTING_LIST + const isSideWindowMissionsActive = + sideWindow.status !== SideWindowStatus.CLOSED && + (sideWindow.selectedPath.menu === SideWindowMenuKey.MISSION_LIST || + sideWindow.selectedPath.menu === SideWindowMenuKey.MISSION_FORM) + const isSideWindowPriorNotificationsActive = + sideWindow.status !== SideWindowStatus.CLOSED && + sideWindow.selectedPath.menu === SideWindowMenuKey.PRIOR_NOTIFICATION_LIST + const isSideWindowBeaconMalfunctionsActive = + sideWindow.status !== SideWindowStatus.CLOSED && + sideWindow.selectedPath.menu === SideWindowMenuKey.BEACON_MALFUNCTION_BOARD + + const toggleFavoriteVesselListDialog = () => { + assertNotNullish(favoriteVesselsButtonRef.current) + + dispatch( + mainWindowActions.toggleLeftDialog({ + key: MapBox.FAVORITE_VESSELS, + topPosition: favoriteVesselsButtonRef.current.getBoundingClientRect().top + }) + ) + } const toggleMissionMenuDialog = () => { - assertNotNullish(missionButtonRef.current) + assertNotNullish(missionsButtonRef.current) dispatch( mainWindowActions.toggleLeftDialog({ key: MapBox.MISSIONS, - topPosition: missionButtonRef.current.getBoundingClientRect().top + topPosition: missionsButtonRef.current.getBoundingClientRect().top }) ) } const toggleSideWindowAlertList = () => { - const isActive = - sideWindow.status !== SideWindowStatus.CLOSED && - sideWindow.selectedPath.menu === SideWindowMenuKey.ALERT_LIST_AND_REPORTING_LIST - if (isActive) { + if (isSideWindowAlertsActive) { dispatch(sideWindowActions.close()) return @@ -61,6 +84,16 @@ export function LeftMenu() { dispatch(openSideWindowPath({ menu: SideWindowMenuKey.ALERT_LIST_AND_REPORTING_LIST })) } + const toggleSideWindowPriorNotificationList = () => { + if (isSideWindowPriorNotificationsActive) { + dispatch(sideWindowActions.close()) + + return + } + + dispatch(openSideWindowPath({ menu: SideWindowMenuKey.PRIOR_NOTIFICATION_LIST })) + } + return ( @@ -69,21 +102,30 @@ export function LeftMenu() { {isFavoriteVesselsLeftMenuButtonDisplayed && ( - - + + {favorites?.length || 0} - + )} {isSuperUser && isMissionsLeftMenuButtonDisplayed && ( - + } + isPriorNotificationLeftMenuButtonDisplayed && ( + + )} - {isSuperUser && isBeaconMalfunctionsLeftMenuButtonDisplayed && } + {isSuperUser && isBeaconMalfunctionsLeftMenuButtonDisplayed && ( + + )} ) @@ -144,14 +198,17 @@ const Block = styled.div` const IconButtonWrapper = styled.div` position: relative; ` -const IconButtonBadge = styled.div<{ +const IconButtonBadge = styled(Figure)<{ $isActive: boolean }>` + align-items: center; background-color: ${p => (p.$isActive ? p.theme.color.charcoal : p.theme.color.gainsboro)}; border-radius: 50%; color: ${p => (p.$isActive ? p.theme.color.white : p.theme.color.gunMetal)}; + display: flex; height: 16px; - left: 40px; + justify-content: center; + left: 38px; line-height: 16px; position: absolute; top: -6px; diff --git a/frontend/src/features/MainWindow/components/MapButtons/BeaconMalfunctionsMapButton.tsx b/frontend/src/features/MainWindow/components/MapButtons/BeaconMalfunctionsMapButton.tsx deleted file mode 100644 index e9284ed4b9..0000000000 --- a/frontend/src/features/MainWindow/components/MapButtons/BeaconMalfunctionsMapButton.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { sideWindowActions } from '@features/SideWindow/slice' -import { openSideWindowPath } from '@features/SideWindow/useCases/openSideWindowPath' -import { useMainAppDispatch } from '@hooks/useMainAppDispatch' -import { useMainAppSelector } from '@hooks/useMainAppSelector' -import { useCallback } from 'react' -import styled from 'styled-components' - -import { MapButton } from './MapButton' -import { SideWindowMenuKey, SideWindowStatus } from '../../../../domain/entities/sideWindow/constants' -import BeaconMalfunctionsSVG from '../../../icons/Icone_VMS.svg?react' - -export function BeaconMalfunctionsMapButton() { - const dispatch = useMainAppDispatch() - const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) - const sideWindow = useMainAppSelector(state => state.sideWindow) - - const isActive = - sideWindow.status !== SideWindowStatus.CLOSED && - sideWindow.selectedPath.menu === SideWindowMenuKey.BEACON_MALFUNCTION_BOARD - - const toggleSideWindow = useCallback(() => { - if (isActive) { - dispatch(sideWindowActions.close()) - - return - } - - dispatch(openSideWindowPath({ menu: SideWindowMenuKey.BEACON_MALFUNCTION_BOARD })) - }, [dispatch, isActive]) - - return ( - - - - ) -} - -const BeaconMalfunctionsButton = styled(MapButton)<{ - $isActive: boolean -}>` - position: absolute; - display: inline-block; - background: ${p => (p.$isActive ? p.theme.color.blueGray : p.theme.color.charcoal)}; - padding: 2px 2px 2px 2px; - top: 280px; - left: 10px; - border-radius: 2px; - height: 40px; - width: 40px; - - &:hover, - &:focus { - background: ${p => (p.$isActive ? p.theme.color.blueGray : p.theme.color.charcoal)}; - } -` - -const BeaconMalfunctionsIcon = styled(BeaconMalfunctionsSVG)` - margin-top: 5px; - width: 25px; - margin-right: 0px; -` diff --git a/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx b/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx deleted file mode 100644 index 7fe15a39a8..0000000000 --- a/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/index.tsx +++ /dev/null @@ -1,190 +0,0 @@ -import { COLORS } from '@constants/constants' -import { useMainAppDispatch } from '@hooks/useMainAppDispatch' -import { useMainAppSelector } from '@hooks/useMainAppSelector' -import { MapBox } from 'domain/entities/map/constants' -import { useRef } from 'react' -import styled from 'styled-components' - -import { FavoriteVessel } from './FavoriteVessel' -import { getVesselCompositeIdentifier } from '../../../../../domain/entities/vessel/vessel' -import { setHideNonSelectedVessels } from '../../../../../domain/shared_slices/Vessel' -import { MapPropertyTrigger } from '../../../../commonComponents/MapPropertyTrigger' -import { MapComponent } from '../../../../commonStyles/MapComponent' -import HidingOtherTracksSVG from '../../../../icons/Bouton_masquer_pistes_actif.svg?react' -import ShowingOtherTracksSVG from '../../../../icons/Bouton_masquer_pistes_inactif.svg?react' -import FavoriteSVG from '../../../../icons/favorite.svg?react' -import { setLeftMapBoxOpened } from '../../../slice' -import { MapButton } from '../MapButton' - -export function FavoriteVessels() { - const dispatch = useMainAppDispatch() - const favorites = useMainAppSelector(state => state.favoriteVessel.favorites) - const { hideNonSelectedVessels, selectedVesselIdentity, vesselsTracksShowed } = useMainAppSelector( - state => state.vessel - ) - const leftMapBoxOpened = useMainAppSelector(state => state.mainWindow.leftMapBoxOpened) - const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) - - const wrapperRef = useRef(null) - - return ( - - - {favorites?.length || 0} - - - dispatch( - setLeftMapBoxOpened(leftMapBoxOpened === MapBox.FAVORITE_VESSELS ? undefined : MapBox.FAVORITE_VESSELS) - ) - } - title="Mes navires suivis" - > - - - -
Mes navires suivis
- {favorites?.length ? ( - - {favorites.map((favoriteVessel, index) => { - const vesselCompositeIdentifier = getVesselCompositeIdentifier(favoriteVessel) - const isTrackShowed = !!Object.values(vesselsTracksShowed)?.find( - vessel => vessel.vesselCompositeIdentifier === vesselCompositeIdentifier - ) - - return ( - - ) - })} - - ) : ( - Aucun navire suivi - )} - dispatch(setHideNonSelectedVessels(isHidden))} - /> -
-
- ) -} - -const FavoriteVesselsNumber = styled(MapComponent)<{ - $isOpen: boolean -}>` - display: inline-block; - position: absolute; - height: 15px; - border-radius: 10px; - top: 64px; - line-height: 14px; - left: 40px; - background-color: ${p => (p.$isOpen ? p.theme.color.charcoal : p.theme.color.gainsboro)}; - transition: all 0.5s; - color: ${p => (p.$isOpen ? p.theme.color.white : p.theme.color.gunMetal)}; - z-index: 100; - padding: 0 4px; - text-align: center; - font-size: 12px; -` - -const List = styled.ul` - margin: 0; - background-color: ${p => p.theme.color.white}; - border-radius: 0; - border-bottom-left-radius: 2px; - border-bottom-right-radius: 2px; - padding: 0; - max-height: 550px; - overflow-x: hidden; - color: ${COLORS.gunMetal}; -` - -const Wrapper = styled.div` - transition: all 0.2s; - z-index: 1000; -` - -const NoVesselInFavorites = styled.div` - font-size: 13px; - margin: 15px; - color: ${COLORS.gunMetal}; -` - -const Header = styled.div<{ - $isFirst: boolean -}>` - background: ${COLORS.charcoal}; - color: ${COLORS.gainsboro}; - padding: 9px 0 7px 15px; - font-size: 16px; - text-align: left; - border-top-left-radius: ${p => (p.$isFirst ? '2px' : '0')}; - border-top-right-radius: ${p => (p.$isFirst ? '2px' : '0')}; -` - -const FavoriteVesselsBox = styled(MapComponent)<{ - $isOpen: boolean -}>` - width: 305px; - background: ${p => p.theme.color.white}; - margin-left: ${p => (p.$isOpen ? '45px' : '-420px')}; - opacity: ${p => (p.$isOpen ? '1' : '0')}; - top: 73px; - left: 10px; - border-radius: 2px; - position: absolute; - display: inline-block; - transition: all 0.5s; -` - -const FavoriteVesselsIcon = styled(MapButton)<{ - $isOpen: boolean -}>` - position: absolute; - display: inline-block; - z-index: 99; - top: 73px; - height: 40px; - width: 40px; - border-radius: 2px; - left: 10px; - background: ${p => (p.$isOpen ? p.theme.color.blueGray : p.theme.color.charcoal)}; - transition: all 0.3s; - - &:hover, - &:focus { - background: ${p => (p.$isOpen ? p.theme.color.blueGray : p.theme.color.charcoal)}; - } -` - -const FavoritesIcon = styled(FavoriteSVG)` - width: 40px; - height: 40px; -` diff --git a/frontend/src/features/MainWindow/components/MapButtons/index.tsx b/frontend/src/features/MainWindow/components/MapButtons/index.tsx index 7f43d325ae..2ee6ba2cd2 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/index.tsx +++ b/frontend/src/features/MainWindow/components/MapButtons/index.tsx @@ -3,37 +3,25 @@ import { ControlUnitListMapButton } from '@features/ControlUnit/components/Contr import { useMainAppSelector } from '@hooks/useMainAppSelector' import { LegacyRsuiteComponentsWrapper } from 'ui/LegacyRsuiteComponentsWrapper' -import { BeaconMalfunctionsMapButton } from './BeaconMalfunctionsMapButton' -import { FavoriteVessels } from './FavoriteVessels' import { VesselFiltersMapButton } from './VesselFilters' import { VesselLabelsMapButton } from './VesselLabels' import { VesselVisibilityMapButton } from './VesselVisibility' import { useIsSuperUser } from '../../../../auth/hooks/useIsSuperUser' import { InterestPointMapButton } from '../../../InterestPoint/components/InterestPointMapButton' import { MeasurementMapButton } from '../../../Measurement/components/MeasurementMapButton' -import { PriorNotificationListButton } from '../../../PriorNotification/components/PriorNotificationListButton' export function MapButtons() { const isSuperUser = useIsSuperUser() const isAccountMapButtonDisplayed = useMainAppSelector(state => state.displayedComponent.isAccountMapButtonDisplayed) - const isBeaconMalfunctionsLeftMenuButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isBeaconMalfunctionsLeftMenuButtonDisplayed - ) const isControlUnitListMapButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isControlUnitListMapButtonDisplayed ) - const isFavoriteVesselsLeftMenuButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isFavoriteVesselsLeftMenuButtonDisplayed - ) const isInterestPointRightMenuButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isInterestPointRightMenuButtonDisplayed ) const isMeasurementRightMenuButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isMeasurementRightMenuButtonDisplayed ) - const isPriorNotificationLeftMenuButtonDisplayed = useMainAppSelector( - state => state.displayedComponent.isPriorNotificationLeftMenuButtonDisplayed - ) const isVesselFiltersRightMenuButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isVesselFiltersRightMenuButtonDisplayed ) @@ -47,11 +35,6 @@ export function MapButtons() { return ( <> - {isFavoriteVesselsLeftMenuButtonDisplayed && } - {(isSuperUser || import.meta.env.FRONTEND_PRIOR_NOTIFICATION_LIST_ENABLED === 'true') && - isPriorNotificationLeftMenuButtonDisplayed && } - {isSuperUser && isBeaconMalfunctionsLeftMenuButtonDisplayed && } - {isVesselFiltersRightMenuButtonDisplayed && } {isVesselVisibilityRightMenuButtonDisplayed && } {isMeasurementRightMenuButtonDisplayed && } diff --git a/frontend/src/features/MainWindow/index.tsx b/frontend/src/features/MainWindow/index.tsx index dac8bcb776..f41c63a0d6 100644 --- a/frontend/src/features/MainWindow/index.tsx +++ b/frontend/src/features/MainWindow/index.tsx @@ -1,4 +1,5 @@ import { MissionMenuDialog } from '@features/Mission/components/MissionMenuDialog' +import { FavoriteVesselListDialog } from '@features/Vessel/components/FavoriteVesselListDialog' import { MapBox } from 'domain/entities/map/constants' import { useCallback } from 'react' import { useBeforeUnload } from 'react-router-dom' @@ -19,7 +20,7 @@ import { DrawLayerModal } from '../Draw/components/DrawModal' import { HealthcheckHeadband } from '../Healthcheck/components/HealthcheckHeadband' import { LayersSidebar } from '../LayersSidebar/components' import { Map } from '../map/Map' -import PreviewFilteredVessels from '../preview_filtered_vessels/PreviewFilteredVessels' +import { PreviewFilteredVessels } from '../preview_filtered_vessels/PreviewFilteredVessels' import { SideWindowLauncher } from '../SideWindow/SideWindowLauncher' import { VesselLoader } from '../Vessel/components/VesselLoader' import { VesselList } from '../VesselList' @@ -34,6 +35,12 @@ export function MainWindow() { state => state.displayedComponent.isControlUnitListDialogDisplayed ) const isDrawLayerModalDisplayed = useMainAppSelector(state => state.displayedComponent.isDrawLayerModalDisplayed) + const isFavoriteVesselsLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isFavoriteVesselsLeftMenuButtonDisplayed + ) + const isMissionsLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isMissionsLeftMenuButtonDisplayed + ) const isVesselListDisplayed = useMainAppSelector(state => state.displayedComponent.isVesselListDisplayed) const isVesselSearchDisplayed = useMainAppSelector(state => state.displayedComponent.isVesselSearchDisplayed) const isVesselSidebarOpen = useMainAppSelector(state => state.vessel.vesselSidebarIsOpen) @@ -88,7 +95,10 @@ export function MainWindow() { {isDrawLayerModalDisplayed && } - {openedLeftDialog?.key === MapBox.MISSIONS && } + {openedLeftDialog?.key === MapBox.FAVORITE_VESSELS && isFavoriteVesselsLeftMenuButtonDisplayed && ( + + )} + {openedLeftDialog?.key === MapBox.MISSIONS && isMissionsLeftMenuButtonDisplayed && }
) } diff --git a/frontend/src/features/Mission/components/MissionMenuDialog.tsx b/frontend/src/features/Mission/components/MissionMenuDialog.tsx index 19569f6381..2ac6129fee 100644 --- a/frontend/src/features/Mission/components/MissionMenuDialog.tsx +++ b/frontend/src/features/Mission/components/MissionMenuDialog.tsx @@ -45,7 +45,7 @@ export function MissionMenuDialog() { } return ( - + Missions et contrôles @@ -74,12 +74,13 @@ export function MissionMenuDialog() { ) } +// TODO Check with Adeline if we plan on keeping the animation (disabled for now). const Wrapper = styled.div` box-sizing: border-box; background-color: ${p => p.theme.color.white}; left: 160px; position: absolute; - transition: all 0.2s; + transition: all 0.5s; width: 320px; * { diff --git a/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/FavoriteVessel.tsx b/frontend/src/features/Vessel/components/FavoriteVesselListDialog/FavoriteVessel.tsx similarity index 87% rename from frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/FavoriteVessel.tsx rename to frontend/src/features/Vessel/components/FavoriteVesselListDialog/FavoriteVessel.tsx index 583470f7da..3f1f4e2fb3 100644 --- a/frontend/src/features/MainWindow/components/MapButtons/FavoriteVessels/FavoriteVessel.tsx +++ b/frontend/src/features/Vessel/components/FavoriteVesselListDialog/FavoriteVessel.tsx @@ -1,15 +1,14 @@ import { CountryFlag } from '@components/CountryFlag' import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { Icon, THEME } from '@mtes-mct/monitor-ui' +import { removeVesselFromFavorites } from 'domain/shared_slices/FavoriteVessel' +import { hideVesselTrack } from 'domain/use_cases/vessel/hideVesselTrack' +import { showVessel } from 'domain/use_cases/vessel/showVessel' +import { showVesselTrack } from 'domain/use_cases/vessel/showVesselTrack' +import { unselectVessel } from 'domain/use_cases/vessel/unselectVessel' import styled from 'styled-components' -import { removeVesselFromFavorites } from '../../../../../domain/shared_slices/FavoriteVessel' -import { hideVesselTrack } from '../../../../../domain/use_cases/vessel/hideVesselTrack' -import { showVessel } from '../../../../../domain/use_cases/vessel/showVessel' -import { showVesselTrack } from '../../../../../domain/use_cases/vessel/showVesselTrack' -import { unselectVessel } from '../../../../../domain/use_cases/vessel/unselectVessel' - -import type { VesselCompositeIdentifier, VesselIdentity } from '../../../../../domain/entities/vessel/types' +import type { VesselCompositeIdentifier, VesselIdentity } from '../../../../domain/entities/vessel/types' type FavoriteVesselProps = Readonly<{ favorite: VesselIdentity diff --git a/frontend/src/features/Vessel/components/FavoriteVesselListDialog/index.tsx b/frontend/src/features/Vessel/components/FavoriteVesselListDialog/index.tsx new file mode 100644 index 0000000000..3c271ebe1b --- /dev/null +++ b/frontend/src/features/Vessel/components/FavoriteVesselListDialog/index.tsx @@ -0,0 +1,105 @@ +import { useMainAppDispatch } from '@hooks/useMainAppDispatch' +import { useMainAppSelector } from '@hooks/useMainAppSelector' +import { assertNotNullish } from '@utils/assertNotNullish' +import styled from 'styled-components' + +import { FavoriteVessel } from './FavoriteVessel' +import { getVesselCompositeIdentifier } from '../../../../domain/entities/vessel/vessel' +import { setHideNonSelectedVessels } from '../../../../domain/shared_slices/Vessel' +import { MapPropertyTrigger } from '../../../commonComponents/MapPropertyTrigger' +import HidingOtherTracksSVG from '../../../icons/Bouton_masquer_pistes_actif.svg?react' +import ShowingOtherTracksSVG from '../../../icons/Bouton_masquer_pistes_inactif.svg?react' + +export function FavoriteVesselListDialog() { + const dispatch = useMainAppDispatch() + const favorites = useMainAppSelector(state => state.favoriteVessel.favorites) + const { hideNonSelectedVessels, selectedVesselIdentity, vesselsTracksShowed } = useMainAppSelector( + state => state.vessel + ) + const openedLeftDialog = useMainAppSelector(state => state.mainWindow.openedLeftDialog) + assertNotNullish(openedLeftDialog) + + return ( + +
Mes navires suivis
+ {favorites?.length ? ( + + {favorites.map((favoriteVessel, index) => { + const vesselCompositeIdentifier = getVesselCompositeIdentifier(favoriteVessel) + const isTrackShowed = !!Object.values(vesselsTracksShowed)?.find( + vessel => vessel.vesselCompositeIdentifier === vesselCompositeIdentifier + ) + + return ( + + ) + })} + + ) : ( + Aucun navire suivi + )} + dispatch(setHideNonSelectedVessels(isHidden))} + /> +
+ ) +} + +// TODO Check with Adeline if we plan on keeping the animation (disabled for now). +const Wrapper = styled.div` + box-sizing: border-box; + background-color: ${p => p.theme.color.white}; + border-radius: 2px; + left: 160px; + position: absolute; + transition: all 0.5s; + width: 305px; + + * { + box-sizing: border-box; + } +` + +const List = styled.ul` + margin: 0; + background-color: ${p => p.theme.color.white}; + border-radius: 0; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + padding: 0; + max-height: 550px; + overflow-x: hidden; + color: ${p => p.theme.color.gunMetal}; +` + +const NoVesselInFavorites = styled.div` + font-size: 13px; + margin: 15px; + color: ${p => p.theme.color.gunMetal}; +` + +const Header = styled.div` + background: ${p => p.theme.color.charcoal}; + color: ${p => p.theme.color.gainsboro}; + padding: 9px 0 7px 15px; + font-size: 16px; + text-align: left; + border-top-left-radius: 2px; + border-top-right-radius: 2px; +` From 489671193635998c1db883e0cb841ca15d30e149 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Mon, 13 May 2024 07:05:22 +0200 Subject: [PATCH 09/16] Move regulations dialog to main window left menu --- .../shared_slices/DisplayedComponent.ts | 2 ++ .../LayersSidebar/components/index.tsx | 6 ++-- .../MainWindow/components/LeftMenu.tsx | 32 +++++++++++++++++-- frontend/src/features/MainWindow/index.tsx | 5 ++- 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/frontend/src/domain/shared_slices/DisplayedComponent.ts b/frontend/src/domain/shared_slices/DisplayedComponent.ts index 5b04f45d83..4435cef622 100644 --- a/frontend/src/domain/shared_slices/DisplayedComponent.ts +++ b/frontend/src/domain/shared_slices/DisplayedComponent.ts @@ -23,6 +23,7 @@ export type DisplayedComponentState = { isMissionsLayerDisplayed: boolean isMissionsLeftMenuButtonDisplayed: boolean isPriorNotificationLeftMenuButtonDisplayed: boolean + isRegulationsLeftMenuButtonDisplayed: boolean isStationLayerDisplayed: boolean isVesselFiltersRightMenuButtonDisplayed: boolean isVesselLabelsRightMenuButtonDisplayed: boolean @@ -50,6 +51,7 @@ export const INITIAL_STATE: DisplayedComponentState = { ), isMissionsLeftMenuButtonDisplayed: true, isPriorNotificationLeftMenuButtonDisplayed: true, + isRegulationsLeftMenuButtonDisplayed: true, isStationLayerDisplayed: false, isVesselFiltersRightMenuButtonDisplayed: true, isVesselLabelsRightMenuButtonDisplayed: true, diff --git a/frontend/src/features/LayersSidebar/components/index.tsx b/frontend/src/features/LayersSidebar/components/index.tsx index 1e258576b6..ad59e2e25d 100644 --- a/frontend/src/features/LayersSidebar/components/index.tsx +++ b/frontend/src/features/LayersSidebar/components/index.tsx @@ -1,6 +1,7 @@ import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { useMainAppSelector } from '@hooks/useMainAppSelector' import { Accent, Icon, IconButton, Size, THEME } from '@mtes-mct/monitor-ui' +import { assertNotNullish } from '@utils/assertNotNullish' import { useEffect } from 'react' import styled from 'styled-components' @@ -22,9 +23,10 @@ export function LayersSidebar() { const regulatoryZoneMetadataPanelIsOpen = useMainAppSelector( state => state.regulatory.regulatoryZoneMetadataPanelIsOpen ) + const openedLeftDialog = useMainAppSelector(state => state.mainWindow.openedLeftDialog) + assertNotNullish(openedLeftDialog) const healthcheckTextWarning = useMainAppSelector(state => state.mainWindow.healthcheckTextWarning) const leftMapBoxOpened = useMainAppSelector(state => state.mainWindow.leftMapBoxOpened) - const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) useEffect(() => { if (leftMapBoxOpened !== MapBox.REGULATIONS) { @@ -36,7 +38,7 @@ export function LayersSidebar() { {namespace => ( <> - + (null) const missionsButtonRef = useRef(null) + const regulationsButtonRef = useRef(null) const dispatch = useMainAppDispatch() const favorites = useMainAppSelector(state => state.favoriteVessel.favorites) @@ -37,6 +38,9 @@ export function LeftMenu() { const isPriorNotificationLeftMenuButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isPriorNotificationLeftMenuButtonDisplayed ) + const isRegulationsLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isRegulationsLeftMenuButtonDisplayed + ) const isSideWindowAlertsActive = sideWindow.status !== SideWindowStatus.CLOSED && @@ -74,6 +78,17 @@ export function LeftMenu() { ) } + const toggleRegulationDialog = () => { + assertNotNullish(regulationsButtonRef.current) + + dispatch( + mainWindowActions.toggleLeftDialog({ + key: MapBox.REGULATIONS, + topPosition: regulationsButtonRef.current.getBoundingClientRect().top + }) + ) + } + const toggleSideWindowAlertList = () => { if (isSideWindowAlertsActive) { dispatch(sideWindowActions.close()) @@ -96,9 +111,20 @@ export function LeftMenu() { return ( - - - + {isRegulationsLeftMenuButtonDisplayed && ( + + + + + + )} {isFavoriteVesselsLeftMenuButtonDisplayed && ( diff --git a/frontend/src/features/MainWindow/index.tsx b/frontend/src/features/MainWindow/index.tsx index f41c63a0d6..30116f022e 100644 --- a/frontend/src/features/MainWindow/index.tsx +++ b/frontend/src/features/MainWindow/index.tsx @@ -41,6 +41,9 @@ export function MainWindow() { const isMissionsLeftMenuButtonDisplayed = useMainAppSelector( state => state.displayedComponent.isMissionsLeftMenuButtonDisplayed ) + const isRegulationsLeftMenuButtonDisplayed = useMainAppSelector( + state => state.displayedComponent.isRegulationsLeftMenuButtonDisplayed + ) const isVesselListDisplayed = useMainAppSelector(state => state.displayedComponent.isVesselListDisplayed) const isVesselSearchDisplayed = useMainAppSelector(state => state.displayedComponent.isVesselSearchDisplayed) const isVesselSidebarOpen = useMainAppSelector(state => state.vessel.vesselSidebarIsOpen) @@ -75,7 +78,6 @@ export function MainWindow() { - {isVesselSearchDisplayed && } @@ -95,6 +97,7 @@ export function MainWindow() { {isDrawLayerModalDisplayed && } + {openedLeftDialog?.key === MapBox.REGULATIONS && isRegulationsLeftMenuButtonDisplayed && } {openedLeftDialog?.key === MapBox.FAVORITE_VESSELS && isFavoriteVesselsLeftMenuButtonDisplayed && ( )} From 8e59df8bfed329a8c25f9a521dccbc50969f4d52 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Mon, 13 May 2024 07:10:19 +0200 Subject: [PATCH 10/16] Set main window left menu left+top position to 12px --- frontend/src/features/MainWindow/components/LeftMenu.tsx | 2 +- frontend/src/features/Mission/components/MissionMenuDialog.tsx | 2 +- .../Vessel/components/FavoriteVesselListDialog/index.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/features/MainWindow/components/LeftMenu.tsx b/frontend/src/features/MainWindow/components/LeftMenu.tsx index 0e48a43e31..58220508a8 100644 --- a/frontend/src/features/MainWindow/components/LeftMenu.tsx +++ b/frontend/src/features/MainWindow/components/LeftMenu.tsx @@ -200,7 +200,7 @@ const Wrapper = styled.div` display: flex; flex-direction: column; position: absolute; - left: 112px; + left: 12px; top: 12px; * { diff --git a/frontend/src/features/Mission/components/MissionMenuDialog.tsx b/frontend/src/features/Mission/components/MissionMenuDialog.tsx index 2ac6129fee..40017555da 100644 --- a/frontend/src/features/Mission/components/MissionMenuDialog.tsx +++ b/frontend/src/features/Mission/components/MissionMenuDialog.tsx @@ -78,7 +78,7 @@ export function MissionMenuDialog() { const Wrapper = styled.div` box-sizing: border-box; background-color: ${p => p.theme.color.white}; - left: 160px; + left: 64px; position: absolute; transition: all 0.5s; width: 320px; diff --git a/frontend/src/features/Vessel/components/FavoriteVesselListDialog/index.tsx b/frontend/src/features/Vessel/components/FavoriteVesselListDialog/index.tsx index 3c271ebe1b..e82dbe10b3 100644 --- a/frontend/src/features/Vessel/components/FavoriteVesselListDialog/index.tsx +++ b/frontend/src/features/Vessel/components/FavoriteVesselListDialog/index.tsx @@ -66,7 +66,7 @@ const Wrapper = styled.div` box-sizing: border-box; background-color: ${p => p.theme.color.white}; border-radius: 2px; - left: 160px; + left: 64px; position: absolute; transition: all 0.5s; width: 305px; From 727a21abf6835be2f184c4330a827622bcd45a0e Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Tue, 10 Sep 2024 13:01:22 +0200 Subject: [PATCH 11/16] Fix TS typings following rebase --- frontend/src/domain/entities/vessel/vessel.ts | 2 +- frontend/src/features/MainWindow/components/LeftMenu.tsx | 4 ++-- .../src/features/Mission/components/MissionMenuDialog.tsx | 2 +- .../components/PriorNotificationListButton.tsx | 2 +- .../features/Regulation/useCases/getAllRegulatoryLayers.ts | 2 +- .../features/Regulation/useCases/searchRegulatoryLayers.ts | 6 ++---- .../src/features/Reporting/useCases/archiveReporting.ts | 2 ++ 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/src/domain/entities/vessel/vessel.ts b/frontend/src/domain/entities/vessel/vessel.ts index 4498e7060a..9c2b805dbc 100644 --- a/frontend/src/domain/entities/vessel/vessel.ts +++ b/frontend/src/domain/entities/vessel/vessel.ts @@ -143,7 +143,7 @@ export class Vessel { } export const getOnlyVesselIdentityProperties = ( - vessel: VesselEnhancedObject | SelectedVessel | VesselTypes.EnrichedVessel | Reporting + vessel: VesselEnhancedObject | SelectedVessel | VesselTypes.EnrichedVessel | Reporting | VesselIdentity ): VesselIdentity => ({ beaconNumber: 'beaconNumber' in vessel && !!vessel.beaconNumber ? vessel.beaconNumber : null, districtCode: 'districtCode' in vessel && !!vessel.districtCode ? vessel.districtCode : null, diff --git a/frontend/src/features/MainWindow/components/LeftMenu.tsx b/frontend/src/features/MainWindow/components/LeftMenu.tsx index 58220508a8..1f92f7682e 100644 --- a/frontend/src/features/MainWindow/components/LeftMenu.tsx +++ b/frontend/src/features/MainWindow/components/LeftMenu.tsx @@ -1,12 +1,12 @@ +import { sideWindowActions } from '@features/SideWindow/slice' import { openSideWindowPath } from '@features/SideWindow/useCases/openSideWindowPath' -import { useIsSuperUser } from '@hooks/authorization/useIsSuperUser' import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { useMainAppSelector } from '@hooks/useMainAppSelector' import { Figure, Icon, IconButton, Size } from '@mtes-mct/monitor-ui' import { assertNotNullish } from '@utils/assertNotNullish' +import { useIsSuperUser } from 'auth/hooks/useIsSuperUser' import { MapBox } from 'domain/entities/map/constants' import { SideWindowMenuKey, SideWindowStatus } from 'domain/entities/sideWindow/constants' -import { sideWindowActions } from 'domain/shared_slices/SideWindow' import { useRef } from 'react' import styled from 'styled-components' diff --git a/frontend/src/features/Mission/components/MissionMenuDialog.tsx b/frontend/src/features/Mission/components/MissionMenuDialog.tsx index 40017555da..f5f43f5e39 100644 --- a/frontend/src/features/Mission/components/MissionMenuDialog.tsx +++ b/frontend/src/features/Mission/components/MissionMenuDialog.tsx @@ -1,4 +1,5 @@ import { addMission } from '@features/Mission/useCases/addMission' +import { sideWindowActions } from '@features/SideWindow/slice' import { openSideWindowPath } from '@features/SideWindow/useCases/openSideWindowPath' import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { useMainAppSelector } from '@hooks/useMainAppSelector' @@ -9,7 +10,6 @@ import styled from 'styled-components' import { SideWindowMenuKey, SideWindowStatus } from '../../../domain/entities/sideWindow/constants' import { setDisplayedComponents } from '../../../domain/shared_slices/DisplayedComponent' -import { sideWindowActions } from '../../../domain/shared_slices/SideWindow' import { mainWindowActions } from '../../MainWindow/slice' export function MissionMenuDialog() { diff --git a/frontend/src/features/PriorNotification/components/PriorNotificationListButton.tsx b/frontend/src/features/PriorNotification/components/PriorNotificationListButton.tsx index f2b72c7eb4..81660a65de 100644 --- a/frontend/src/features/PriorNotification/components/PriorNotificationListButton.tsx +++ b/frontend/src/features/PriorNotification/components/PriorNotificationListButton.tsx @@ -17,7 +17,7 @@ import { SideWindowMenuKey, SideWindowStatus } from '../../../domain/entities/si export function PriorNotificationListButton() { const isSuperUser = useIsSuperUser() const dispatch = useMainAppDispatch() - const previewFilteredVesselsMode = useMainAppSelector(state => state.global.previewFilteredVesselsMode) + const previewFilteredVesselsMode = useMainAppSelector(state => state.mainWindow.previewFilteredVesselsMode) const sideWindow = useMainAppSelector(state => state.sideWindow) const { data } = useGetPriorNotificationsToVerifyQuery(isSuperUser ? undefined : skipToken, { diff --git a/frontend/src/features/Regulation/useCases/getAllRegulatoryLayers.ts b/frontend/src/features/Regulation/useCases/getAllRegulatoryLayers.ts index c5878a33ba..e8c9922534 100644 --- a/frontend/src/features/Regulation/useCases/getAllRegulatoryLayers.ts +++ b/frontend/src/features/Regulation/useCases/getAllRegulatoryLayers.ts @@ -1,6 +1,6 @@ import { getAllRegulatoryLayersFromAPI } from '@api/geoserver' +import { setError } from '@features/MainWindow/slice' -import { setError } from '../../../domain/shared_slices/Global' import layer from '../../../domain/shared_slices/Layer' import { MonitorFishWorker } from '../../../workers/MonitorFishWorker' import { diff --git a/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts b/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts index 61e52c9849..ed5e541322 100644 --- a/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts +++ b/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts @@ -6,7 +6,6 @@ import { MonitorFishWorker } from '../../../workers/MonitorFishWorker' import { REGULATION_SEARCH_OPTIONS } from '../components/RegulationSearch/constants' import type { RegulatoryLawTypes, RegulatoryZone } from '../types' -import type { MainAppThunk } from '@store' export const MINIMUM_SEARCH_CHARACTERS_NUMBER = 2 @@ -14,10 +13,9 @@ export const MINIMUM_SEARCH_CHARACTERS_NUMBER = 2 * Search for regulatory zones in the regulatory referential, by zone (geometry) and by the input filters */ export const searchRegulatoryLayers = - (searchQuery: string | undefined): MainAppThunk => + (searchQuery: string | undefined) => async (_, getState): Promise => { const monitorFishWorker = await MonitorFishWorker - const { regulatoryZones } = getState().regulatory const { zoneSelected } = getState().regulatoryLayerSearch const { speciesByCode } = getState().species @@ -26,7 +24,7 @@ export const searchRegulatoryLayers = const extent = getExtentFromGeoJSON(zoneSelected.feature) if (extent?.length === 4) { - return getRegulatoryZonesInExtentFromAPI(extent, getState().mainWindow.isBackoffice) + return getRegulatoryZonesInExtentFromAPI(extent, getState().global.isBackoffice) .then(features => monitorFishWorker.mapGeoserverToRegulatoryZones(features, speciesByCode)) .then(filteredRegulatoryZones => { if (!searchQuery || searchQuery.length < MINIMUM_SEARCH_CHARACTERS_NUMBER) { diff --git a/frontend/src/features/Reporting/useCases/archiveReporting.ts b/frontend/src/features/Reporting/useCases/archiveReporting.ts index 67be0ff8a1..293ce9990a 100644 --- a/frontend/src/features/Reporting/useCases/archiveReporting.ts +++ b/frontend/src/features/Reporting/useCases/archiveReporting.ts @@ -2,6 +2,7 @@ import { archiveReportingFromAPI } from '@api/reporting' import { ReportingType } from '@features/Reporting/types' import { getVesselReportings } from '@features/Reporting/useCases/getVesselReportings' import { DisplayedErrorKey } from '@libs/DisplayedError/constants' +import { assertNotNullish } from '@utils/assertNotNullish' import { Vessel } from '../../../domain/entities/vessel/vessel' import { removeVesselReporting } from '../../../domain/shared_slices/Vessel' @@ -14,6 +15,7 @@ export const archiveReporting = (id: number, type: ReportingType): MainAppThunk => async (dispatch, getState) => { const { selectedVesselIdentity } = getState().vessel + assertNotNullish(selectedVesselIdentity) try { await archiveReportingFromAPI(id) From b40e4b728e3da20b802094a3fa98f723ddef7909 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Tue, 10 Sep 2024 13:55:34 +0200 Subject: [PATCH 12/16] Rollback breaking auto-lint of InterestPointLayer --- .../layers/InterestPointLayer.jsx | 241 +++++++++--------- 1 file changed, 116 insertions(+), 125 deletions(-) diff --git a/frontend/src/features/InterestPoint/layers/InterestPointLayer.jsx b/frontend/src/features/InterestPoint/layers/InterestPointLayer.jsx index cd65fad2e0..020146b6d0 100644 --- a/frontend/src/features/InterestPoint/layers/InterestPointLayer.jsx +++ b/frontend/src/features/InterestPoint/layers/InterestPointLayer.jsx @@ -1,19 +1,13 @@ import { usePrevious } from '@mtes-mct/monitor-ui' -import GeoJSON from 'ol/format/GeoJSON' -import LineString from 'ol/geom/LineString' -import Draw from 'ol/interaction/Draw' -import VectorLayer from 'ol/layer/Vector' -import { getLength } from 'ol/sphere' import { useEffect, useRef, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { v4 as uuidv4 } from 'uuid' -import { getInterestPointStyle, POIStyle } from './interestPoint.style' -import { InterestPointLine } from './interestPointLine' -import { LayerProperties } from '../../../domain/entities/layers/constants' +import { useDispatch, useSelector } from 'react-redux' +import VectorSource from 'ol/source/Vector' import { MapBox, OPENLAYERS_PROJECTION } from '../../../domain/entities/map/constants' -import saveInterestPointFeature from '../../../domain/use_cases/interestPoint/saveInterestPointFeature' -import { monitorfishMap } from '../../map/monitorfishMap' +import Draw from 'ol/interaction/Draw' +import VectorLayer from 'ol/layer/Vector' +import { getInterestPointStyle, POIStyle } from './interestPoint.style' +import { v4 as uuidv4 } from 'uuid' import { InterestPointOverlay } from '../components/InterestPointOverlay' import { deleteInterestPointBeingDrawed, @@ -24,7 +18,19 @@ import { updateInterestPointBeingDrawed, updateInterestPointKeyBeingDrawed } from '../slice' -import { coordinatesAreModified, coordinatesOrTypeAreModified, InterestPointType } from '../utils' +import { + coordinatesAreModified, + coordinatesOrTypeAreModified, + InterestPointType +} from '../utils' +import saveInterestPointFeature from '../../../domain/use_cases/interestPoint/saveInterestPointFeature' +import GeoJSON from 'ol/format/GeoJSON' +import LineString from 'ol/geom/LineString' +import { InterestPointLine } from './interestPointLine' +import { getLength } from 'ol/sphere' +import { LayerProperties } from '../../../domain/entities/layers/constants' +import { setRightMapBoxOpened } from '../../../features/MainWindow/slice' +import { monitorfishMap } from '../../map/monitorfishMap' const DRAW_START_EVENT = 'drawstart' const DRAW_ABORT_EVENT = 'drawabort' @@ -32,46 +38,44 @@ const DRAW_END_EVENT = 'drawend' export const MIN_ZOOM = 7 -function InterestPointLayer({ mapMovingAndZoomEvent }) { +const InterestPointLayer = ({ mapMovingAndZoomEvent }) => { const dispatch = useDispatch() const { - interestPointBeingDrawed, - interestPoints, - /** @type {InterestPoint | null} interestPointBeingDrawed */ isDrawing, - /** @type {InterestPoint[]} interestPoints */ isEditing, + /** @type {InterestPoint | null} interestPointBeingDrawed */ + interestPointBeingDrawed, + /** @type {InterestPoint[]} interestPoints */ + interestPoints, triggerInterestPointFeatureDeletion } = useSelector(state => state.interestPoint) const [drawObject, setDrawObject] = useState(null) const vectorSourceRef = useRef(null) - function getVectorSource() { + function getVectorSource () { if (vectorSourceRef.current === null) { vectorSourceRef.current = new VectorSource({ - projection: OPENLAYERS_PROJECTION, - wrapX: false + wrapX: false, + projection: OPENLAYERS_PROJECTION }) } - return vectorSourceRef.current } const layerRef = useRef(null) - function getLayer() { + function getLayer () { if (layerRef.current === null) { layerRef.current = new VectorLayer({ - renderBuffer: 7, source: getVectorSource(), - style: (feature, resolution) => getInterestPointStyle(feature, resolution), + renderBuffer: 7, updateWhileAnimating: true, updateWhileInteracting: true, + style: (feature, resolution) => getInterestPointStyle(feature, resolution), zIndex: LayerProperties.INTEREST_POINT.zIndex }) } - return layerRef.current } @@ -80,7 +84,7 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { const previousInterestPointBeingDrawed = usePrevious(interestPointBeingDrawed) useEffect(() => { - function addLayerToMap() { + function addLayerToMap () { monitorfishMap.getLayers().push(getLayer()) return () => { @@ -92,24 +96,22 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { }, []) useEffect(() => { - function drawExistingFeaturesOnMap() { + function drawExistingFeaturesOnMap () { if (interestPoints) { - const features = interestPoints - .map(interestPoint => { - if (interestPoint.feature) { - const nextFeature = new GeoJSON({ - featureProjection: OPENLAYERS_PROJECTION - }).readFeature(interestPoint.feature) + const features = interestPoints.map(interestPoint => { + if (interestPoint.feature) { + const nextFeature = new GeoJSON({ + featureProjection: OPENLAYERS_PROJECTION + }).readFeature(interestPoint.feature) - const { feature, ...interestPointWithoutFeature } = interestPoint - nextFeature.setProperties(interestPointWithoutFeature) + const { feature, ...interestPointWithoutFeature } = interestPoint + nextFeature.setProperties(interestPointWithoutFeature) - return nextFeature - } + return nextFeature + } - return null - }) - .filter(feature => feature) + return null + }).filter(feature => feature) getVectorSource().addFeatures(features) } @@ -120,23 +122,21 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { useEffect(() => { if (isDrawing) { - function addEmptyNextInterestPoint() { - dispatch( - updateInterestPointBeingDrawed({ - coordinates: null, - name: null, - observations: null, - type: InterestPointType.FISHING_VESSEL, - uuid: uuidv4() - }) - ) + function addEmptyNextInterestPoint () { + dispatch(updateInterestPointBeingDrawed({ + uuid: uuidv4(), + name: null, + type: InterestPointType.FISHING_VESSEL, + coordinates: null, + observations: null + })) } - function drawNewFeatureOnMap() { + function drawNewFeatureOnMap () { const draw = new Draw({ source: getVectorSource(), - style: POIStyle, - type: 'Point' + type: 'Point', + style: POIStyle }) monitorfishMap.addInteraction(draw) @@ -149,11 +149,11 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { }, [isDrawing]) useEffect(() => { - function removeInteraction() { + function removeInteraction () { if (!isDrawing && drawObject) { setDrawObject(null) - function waitForUnwantedZoomAndQuitInteraction() { + function waitForUnwantedZoomAndQuitInteraction () { setTimeout(() => { monitorfishMap.removeInteraction(drawObject) }, 300) @@ -167,19 +167,17 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { }, [isDrawing]) useEffect(() => { - function handleDrawEvents() { + function handleDrawEvents () { if (drawObject) { drawObject.once(DRAW_START_EVENT, event => { - function startDrawing(event, type) { - dispatch( - updateInterestPointBeingDrawed({ - coordinates: event.feature.getGeometry().getLastCoordinate(), - name: null, - observations: null, - type, - uuid: interestPointBeingDrawed.uuid - }) - ) + function startDrawing (event, type) { + dispatch(updateInterestPointBeingDrawed({ + uuid: interestPointBeingDrawed.uuid, + name: null, + type: type, + coordinates: event.feature.getGeometry().getLastCoordinate(), + observations: null + })) } if (interestPointBeingDrawed) { @@ -204,7 +202,7 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { }, [drawObject, interestPointBeingDrawed]) useEffect(() => { - function showOrHideInterestPointsOverlays() { + function showOrHideInterestPointsOverlays () { const currentZoom = monitorfishMap.getView().getZoom().toFixed(2) if (currentZoom !== previousMapZoom.current) { previousMapZoom.current = currentZoom @@ -231,7 +229,7 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { }, [triggerInterestPointFeatureDeletion]) useEffect(() => { - function modifyFeatureWhenCoordinatesOrTypeModified() { + function modifyFeatureWhenCoordinatesOrTypeModified () { if (interestPointBeingDrawed?.coordinates?.length && interestPointBeingDrawed?.uuid) { const drawingFeatureToUpdate = getVectorSource().getFeatureById(interestPointBeingDrawed.uuid) @@ -240,16 +238,13 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { drawingFeatureToUpdate.getGeometry().setCoordinates(interestPointWithoutFeature.coordinates) drawingFeatureToUpdate.setProperties(interestPointWithoutFeature) - const nextFeature = new GeoJSON().writeFeatureObject(drawingFeatureToUpdate, { - featureProjection: OPENLAYERS_PROJECTION - }) + const nextFeature = new GeoJSON() + .writeFeatureObject(drawingFeatureToUpdate, { featureProjection: OPENLAYERS_PROJECTION }) - dispatch( - updateInterestPointKeyBeingDrawed({ - key: 'feature', - value: nextFeature - }) - ) + dispatch(updateInterestPointKeyBeingDrawed({ + key: 'feature', + value: nextFeature + })) } } } @@ -258,16 +253,9 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { }, [interestPointBeingDrawed?.coordinates, interestPointBeingDrawed?.type]) useEffect(() => { - function initLineWhenInterestPointCoordinatesModified() { - if ( - interestPointBeingDrawed && - previousInterestPointBeingDrawed && - coordinatesAreModified(interestPointBeingDrawed, previousInterestPointBeingDrawed) - ) { - const line = new LineString([ - interestPointBeingDrawed.coordinates, - previousInterestPointBeingDrawed.coordinates - ]) + function initLineWhenInterestPointCoordinatesModified () { + if (interestPointBeingDrawed && previousInterestPointBeingDrawed && coordinatesAreModified(interestPointBeingDrawed, previousInterestPointBeingDrawed)) { + const line = new LineString([interestPointBeingDrawed.coordinates, previousInterestPointBeingDrawed.coordinates]) const distance = getLength(line, { projection: OPENLAYERS_PROJECTION }) if (distance > 10) { @@ -276,9 +264,7 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { interestPointToCoordinates.delete(featureId) const feature = getVectorSource().getFeatureById(featureId) if (feature) { - feature.setGeometry( - new LineString([interestPointBeingDrawed.coordinates, interestPointBeingDrawed.coordinates]) - ) + feature.setGeometry(new LineString([interestPointBeingDrawed.coordinates, interestPointBeingDrawed.coordinates])) } } } @@ -288,7 +274,7 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { initLineWhenInterestPointCoordinatesModified() }, [interestPointBeingDrawed]) - function deleteInterestPoint(uuid) { + function deleteInterestPoint (uuid) { const feature = getVectorSource().getFeatureById(uuid) if (feature) { getVectorSource().removeFeature(feature) @@ -304,7 +290,7 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { dispatch(removeInterestPoint(uuid)) } - function moveInterestPointLine(uuid, coordinates, nextCoordinates, offset) { + function moveInterestPointLine (uuid, coordinates, nextCoordinates, offset) { const featureId = InterestPointLine.getFeatureId(uuid) if (interestPointToCoordinates.has(featureId)) { @@ -313,13 +299,14 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { if (existingLabelLineFeature) { if (interestPointFeature) { - existingLabelLineFeature.setGeometry( - new LineString([interestPointFeature.getGeometry().getCoordinates(), nextCoordinates]) - ) + existingLabelLineFeature.setGeometry(new LineString([interestPointFeature.getGeometry().getCoordinates(), nextCoordinates])) } } } else { - const interestPointLineFeature = InterestPointLine.getFeature(coordinates, nextCoordinates, featureId) + const interestPointLineFeature = InterestPointLine.getFeature( + coordinates, + nextCoordinates, + featureId) getVectorSource().addFeature(interestPointLineFeature) } @@ -329,12 +316,12 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { setInterestPointToCoordinates(nextVesselToCoordinates) } - function modifyInterestPoint(uuid) { + function modifyInterestPoint (uuid) { dispatch(editInterestPoint(uuid)) dispatch(setRightMapBoxOpened(MapBox.INTEREST_POINT)) } - function deleteInterestPointBeingDrawedAndCloseTool() { + function deleteInterestPointBeingDrawedAndCloseTool () { dispatch(endInterestPointDraw()) dispatch(setRightMapBoxOpened(undefined)) dispatch(deleteInterestPointBeingDrawed()) @@ -343,40 +330,44 @@ function InterestPointLayer({ mapMovingAndZoomEvent }) { return ( <>
- {interestPoints && Array.isArray(interestPoints) - ? interestPoints.map(interestPoint => ( - { + return - )) - : null} - {interestPointBeingDrawed && !isEditing ? ( - {}} - moveLine={moveInterestPointLine} - name={interestPointBeingDrawed.name} - observations={interestPointBeingDrawed.observations} - uuid={interestPointBeingDrawed.uuid} - zoomHasChanged={previousMapZoom.current} - /> - ) : null} + }) + : null + } + { + interestPointBeingDrawed && !isEditing + ? {}} + zoomHasChanged={previousMapZoom.current} + moveLine={moveInterestPointLine} + /> + : null + }
) } -export default InterestPointLayer +export default InterestPointLayer \ No newline at end of file From 28a85e4836a95c56a74dab70921a4d7b66a71ddb Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Tue, 10 Sep 2024 13:57:31 +0200 Subject: [PATCH 13/16] Add @types/uuid dev dep in Frontend --- frontend/package-lock.json | 8 ++++++++ frontend/package.json | 1 + 2 files changed, 9 insertions(+) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dee3cb596c..8a8444b67d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -78,6 +78,7 @@ "@types/react": "18.3.5", "@types/react-dom": "18.3.0", "@types/styled-components": "5.1.34", + "@types/uuid": "10.0.0", "@typescript-eslint/eslint-plugin": "6.2.1", "@typescript-eslint/parser": "6.2.1", "@vitejs/plugin-react": "4.3.1", @@ -4510,6 +4511,13 @@ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", "license": "MIT" }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/yargs": { "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", diff --git a/frontend/package.json b/frontend/package.json index 9f07b694b9..5850d38acf 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -104,6 +104,7 @@ "@types/react": "18.3.5", "@types/react-dom": "18.3.0", "@types/styled-components": "5.1.34", + "@types/uuid": "10.0.0", "@typescript-eslint/eslint-plugin": "6.2.1", "@typescript-eslint/parser": "6.2.1", "@vitejs/plugin-react": "4.3.1", From 3927fba5698ddec0e723080860464bf1e19b1d99 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Tue, 10 Sep 2024 14:08:22 +0200 Subject: [PATCH 14/16] Fix features store path in getAllRegulatoryLayers() use case --- .../Regulation/useCases/getAllRegulatoryLayers.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/features/Regulation/useCases/getAllRegulatoryLayers.ts b/frontend/src/features/Regulation/useCases/getAllRegulatoryLayers.ts index e8c9922534..6b3f3c18c1 100644 --- a/frontend/src/features/Regulation/useCases/getAllRegulatoryLayers.ts +++ b/frontend/src/features/Regulation/useCases/getAllRegulatoryLayers.ts @@ -10,13 +10,15 @@ import { setSelectedRegulatoryZone } from '../slice' -export const getAllRegulatoryLayers = () => async (dispatch, getState) => { +import type { MainAppThunk } from '@store' + +export const getAllRegulatoryLayers = (): MainAppThunk> => async (dispatch, getState) => { const monitorFishWorker = await MonitorFishWorker const { setShowedLayersWithLocalStorageValues } = layer.homepage.actions const { speciesByCode } = getState().species try { - const features = await getAllRegulatoryLayersFromAPI(getState().global.isBackoffice) + const features = await getAllRegulatoryLayersFromAPI(getState().mainWindow.isBackoffice) monitorFishWorker.mapGeoserverToRegulatoryZones(features, speciesByCode).then(regulatoryZones => { dispatch(setRegulatoryZones(regulatoryZones)) @@ -28,6 +30,8 @@ export const getAllRegulatoryLayers = () => async (dispatch, getState) => { dispatch(setLayersTopicsByRegTerritory(layersTopicsByRegulatoryTerritory)) dispatch(setRegulatoryLayerLawTypes(layersTopicsByRegulatoryTerritory)) dispatch(setSelectedRegulatoryZone(layersWithoutGeometry)) + // TODO Investigate this dubious pattern/line of code. + // @ts-ignore dispatch(setShowedLayersWithLocalStorageValues?.({ namespace: 'homepage', regulatoryZones: layersWithoutGeometry })) } catch (error) { console.error(error) From 3b3b74b07c454af1fa910b2c331269951a812372 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Tue, 10 Sep 2024 14:10:21 +0200 Subject: [PATCH 15/16] Fix features store path in searchRegulatoryLayers() use case --- .../features/Regulation/useCases/searchRegulatoryLayers.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts b/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts index ed5e541322..1358c84d4b 100644 --- a/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts +++ b/frontend/src/features/Regulation/useCases/searchRegulatoryLayers.ts @@ -6,6 +6,7 @@ import { MonitorFishWorker } from '../../../workers/MonitorFishWorker' import { REGULATION_SEARCH_OPTIONS } from '../components/RegulationSearch/constants' import type { RegulatoryLawTypes, RegulatoryZone } from '../types' +import type { MainAppThunk } from '@store' export const MINIMUM_SEARCH_CHARACTERS_NUMBER = 2 @@ -13,8 +14,8 @@ export const MINIMUM_SEARCH_CHARACTERS_NUMBER = 2 * Search for regulatory zones in the regulatory referential, by zone (geometry) and by the input filters */ export const searchRegulatoryLayers = - (searchQuery: string | undefined) => - async (_, getState): Promise => { + (searchQuery: string | undefined): MainAppThunk> => + async (_, getState) => { const monitorFishWorker = await MonitorFishWorker const { regulatoryZones } = getState().regulatory const { zoneSelected } = getState().regulatoryLayerSearch @@ -24,7 +25,7 @@ export const searchRegulatoryLayers = const extent = getExtentFromGeoJSON(zoneSelected.feature) if (extent?.length === 4) { - return getRegulatoryZonesInExtentFromAPI(extent, getState().global.isBackoffice) + return getRegulatoryZonesInExtentFromAPI(extent, getState().mainWindow.isBackoffice) .then(features => monitorFishWorker.mapGeoserverToRegulatoryZones(features, speciesByCode)) .then(filteredRegulatoryZones => { if (!searchQuery || searchQuery.length < MINIMUM_SEARCH_CHARACTERS_NUMBER) { From c40f6d922e9f5dc44d02c264d26f5a5ff8174480 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Tue, 10 Sep 2024 14:14:15 +0200 Subject: [PATCH 16/16] Remove legacy LayerSidebar main window left menu button --- .../LayersSidebar/components/index.tsx | 93 ++++++------------- 1 file changed, 26 insertions(+), 67 deletions(-) diff --git a/frontend/src/features/LayersSidebar/components/index.tsx b/frontend/src/features/LayersSidebar/components/index.tsx index ad59e2e25d..69a849f1aa 100644 --- a/frontend/src/features/LayersSidebar/components/index.tsx +++ b/frontend/src/features/LayersSidebar/components/index.tsx @@ -1,6 +1,6 @@ import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { useMainAppSelector } from '@hooks/useMainAppSelector' -import { Accent, Icon, IconButton, Size, THEME } from '@mtes-mct/monitor-ui' +import { THEME } from '@mtes-mct/monitor-ui' import { assertNotNullish } from '@utils/assertNotNullish' import { useEffect } from 'react' import styled from 'styled-components' @@ -11,8 +11,6 @@ import { AdministrativeZones } from '../../AdministrativeZone/components/Adminis import { BaseMaps } from '../../BaseMap/components/BaseMaps' import { MapComponent } from '../../commonStyles/MapComponent' import { CustomZones } from '../../CustomZone/components/CustomZones' -import { MapButton } from '../../MainWindow/components/MapButtons/MapButton' -import { setLeftMapBoxOpened } from '../../MainWindow/slice' import { RegulationSearch } from '../../Regulation/components/RegulationSearch' import { RegulatoryZoneMetadata } from '../../Regulation/components/RegulatoryZoneMetadata' import { RegulatoryZones } from '../../Regulation/components/RegulatoryZones' @@ -23,10 +21,10 @@ export function LayersSidebar() { const regulatoryZoneMetadataPanelIsOpen = useMainAppSelector( state => state.regulatory.regulatoryZoneMetadataPanelIsOpen ) - const openedLeftDialog = useMainAppSelector(state => state.mainWindow.openedLeftDialog) - assertNotNullish(openedLeftDialog) const healthcheckTextWarning = useMainAppSelector(state => state.mainWindow.healthcheckTextWarning) const leftMapBoxOpened = useMainAppSelector(state => state.mainWindow.leftMapBoxOpened) + const openedLeftDialog = useMainAppSelector(state => state.mainWindow.openedLeftDialog) + assertNotNullish(openedLeftDialog) useEffect(() => { if (leftMapBoxOpened !== MapBox.REGULATIONS) { @@ -37,45 +35,35 @@ export function LayersSidebar() { return ( {namespace => ( - <> - - - dispatch(setLeftMapBoxOpened(leftMapBoxOpened === MapBox.REGULATIONS ? undefined : MapBox.REGULATIONS)) - } - size={Size.LARGE} - title="Arbre des couches" - /> - - + + + + + + + + - - - - - - - - - - - - + + +
)}
) } +const Wrapper = styled(MapComponent)` + border-radius: 2px; + background-color: ${p => p.theme.color.white}; + left: 64px; + position: absolute; + transition: all 0.5s; + width: 320px; +` + const RegulatoryZoneMetadataShifter = styled.div<{ $isLeftMapBoxOpened: boolean $isOpen: boolean @@ -96,21 +84,6 @@ const RegulatoryZoneMetadataShifter = styled.div<{ transition: all 0.5s; ` -const Sidebar = styled(MapComponent)<{ - $isOpen: boolean - $isVisible: boolean -}>` - margin-left: ${p => (p.$isOpen ? 0 : '-418px')}; - opacity: ${p => (p.$isVisible ? 1 : 0)}; - top: 10px; - left: 57px; - z-index: 999; - border-radius: 2px; - position: absolute; - display: inline-block; - transition: 0.5s all; -` - const Layers = styled.div<{ $hasHealthcheckTextWarning: boolean }>` @@ -118,17 +91,3 @@ const Layers = styled.div<{ width: 350px; max-height: calc(100vh - ${p => (p.$hasHealthcheckTextWarning ? '210px' : '160px')}); ` - -const SidebarLayersButton = styled(MapButton)` - position: absolute; - top: 10px; - left: 10px; -` - -const SidebarLayersIcon = styled(IconButton)<{ $isActive: boolean }>` - border-radius: 2px; - width: 40px; - height: 40px; - ${p => (p.$isActive ? `background: ${p.theme.color.blueGray};` : '')} - ${p => (p.$isActive ? `border-color: ${p.theme.color.blueGray};` : '')} -`