diff --git a/frontend/cypress/e2e/side_window/mission_form/mission_actions.spec.ts b/frontend/cypress/e2e/side_window/mission_form/mission_actions.spec.ts index 24277dc6e..23d075abd 100644 --- a/frontend/cypress/e2e/side_window/mission_form/mission_actions.spec.ts +++ b/frontend/cypress/e2e/side_window/mission_form/mission_actions.spec.ts @@ -622,7 +622,7 @@ context('Side Window > Mission Form > Mission actions', () => { }) }) - it('Should keep pending action when switching tabs', () => { + it('Should keep pending action and pending infraction form when switching tabs', () => { createPendingMission().then(({ body }) => { const mission = body @@ -646,7 +646,6 @@ context('Side Window > Mission Form > Mission actions', () => { cy.getDataCy('mission-0').first().click({ force: true }) cy.getDataCy('mission-1').first().click({ force: true }) - cy.clickButton('Editer') cy.get('input[name="envActions[0].infractions[0].mmsi"]').should('have.value', '123456789') cy.get('input[name="envActions[0].infractions[0].vesselName"]').should('have.value', 'BALTIK') cy.get('input[name="envActions[0].infractions[0].imo"]').should('have.value', 'IMO123') diff --git a/frontend/src/domain/use_cases/missions/switchTab.ts b/frontend/src/domain/use_cases/missions/switchTab.ts index 95a00276d..d032f2552 100644 --- a/frontend/src/domain/use_cases/missions/switchTab.ts +++ b/frontend/src/domain/use_cases/missions/switchTab.ts @@ -5,29 +5,33 @@ import { sideWindowActions } from '../../../features/SideWindow/slice' import { getIdTyped } from '../../../utils/getIdTyped' import { getMissionPageRoute } from '../../../utils/routes' -export const switchTab = (path: string) => async (dispatch, getState) => { - const { missions } = getState().missionForms +import type { HomeAppThunk } from '@store/index' - const routeParams = getMissionPageRoute(path) - const id = getIdTyped(routeParams?.params.id) +export const switchTab = + (path: string): HomeAppThunk => + async (dispatch, getState) => { + const { missions } = getState().missionForms - // if we want to switch to mission list - if (!id) { - await dispatch(sideWindowActions.setCurrentPath(path)) - await dispatch(missionActions.resetSelectedMissionIdOnMap()) - await dispatch(missionFormsActions.resetActiveMissionId()) + const routeParams = getMissionPageRoute(path) + const id = getIdTyped(routeParams?.params.id) - return - } + // if we want to switch to mission list + if (!id) { + dispatch(sideWindowActions.setCurrentPath(path)) + dispatch(missionActions.resetSelectedMissionIdOnMap()) + dispatch(missionFormsActions.resetActiveMissionId()) + + return + } - await dispatch(missionFormsActions.setActiveMissionId(id)) - await dispatch(missionActions.setSelectedMissionIdOnMap(id)) + dispatch(missionFormsActions.setActiveMissionId(id)) + dispatch(missionActions.setSelectedMissionIdOnMap(id)) - // since we are switching to another mission, we need to update the attached reportings store - // because it's the form who listen to this store - await dispatch( - attachReportingToMissionSliceActions.setAttachedReportings(missions[id]?.missionForm?.attachedReportings || []) - ) + dispatch(sideWindowActions.setCurrentPath(path)) - await dispatch(sideWindowActions.setCurrentPath(path)) -} + // since we are switching to another mission, we need to update the attached reportings store + // because it's the form who listen to this store + dispatch( + attachReportingToMissionSliceActions.setAttachedReportings(missions[id]?.missionForm?.attachedReportings || []) + ) + } diff --git a/frontend/src/features/missions/MissionForm/ActionForm/ControlForm/InfractionsForm.tsx b/frontend/src/features/missions/MissionForm/ActionForm/ControlForm/InfractionsForm.tsx index 944228a49..4a7892a2f 100644 --- a/frontend/src/features/missions/MissionForm/ActionForm/ControlForm/InfractionsForm.tsx +++ b/frontend/src/features/missions/MissionForm/ActionForm/ControlForm/InfractionsForm.tsx @@ -1,3 +1,5 @@ +import { useAppDispatch } from '@hooks/useAppDispatch' +import { useAppSelector } from '@hooks/useAppSelector' import { Accent, Button } from '@mtes-mct/monitor-ui' import { useState } from 'react' import styled from 'styled-components' @@ -5,38 +7,58 @@ import styled from 'styled-components' import { InfractionCard } from './InfractionCard' import { InfractionForm } from './InfractionForm/InfractionForm' import { infractionFactory } from '../../../Missions.helpers' +import { missionFormsActions } from '../../slice' import type { Infraction } from '../../../../../domain/entities/missions' export function InfractionsForm({ canAddInfraction, envActionIndex, form, push, remove }) { + const dispatch = useAppDispatch() + const infractions: Array = form?.values.envActions[envActionIndex]?.infractions ?? [] - const [currentInfractionIndex, setCurrentInfractionIndex] = useState(undefined) + + const activeMissionId = useAppSelector(state => state.missionForms.activeMissionId) + + const selectedMission = useAppSelector(state => + activeMissionId ? state.missionForms.missions[activeMissionId] : undefined + ) + + const activeInfractionId = selectedMission?.activeAction?.activeInfractionId + + const infractionIndex = infractions.findIndex(infraction => infraction.id === activeInfractionId) + + const [currentInfractionIndex, setCurrentInfractionIndex] = useState(infractionIndex) const handleAddInfraction = () => { const numberOfInfractions = infractions?.length || 0 - push(infractionFactory()) + const newInfraction = infractionFactory() + push(newInfraction) setCurrentInfractionIndex(numberOfInfractions) + dispatch(missionFormsActions.setActiveInfractionId(newInfraction.id)) } const handleValidate = () => { setCurrentInfractionIndex(undefined) + dispatch(missionFormsActions.setActiveInfractionId(undefined)) } - const handleEditInfraction = index => () => { + const handleEditInfraction = (index, id: string) => () => { setCurrentInfractionIndex(index) + dispatch(missionFormsActions.setActiveInfractionId(id)) } const handleRemoveInfraction = index => () => { setCurrentInfractionIndex(undefined) + dispatch(missionFormsActions.setActiveInfractionId(undefined)) remove(index) } - const handleDuplicateInfraction = index => () => { + const handleDuplicateInfraction = (index, id: string) => () => { const numberOfInfractions = infractions.length || 0 const selectedInfraction = infractions[index] push(infractionFactory(selectedInfraction)) setCurrentInfractionIndex(numberOfInfractions) + dispatch(missionFormsActions.setActiveInfractionId(id)) } return ( @@ -50,10 +72,10 @@ export function InfractionsForm({ canAddInfraction, envActionIndex, form, push, {form?.values.envActions?.length > 0 && infractions.length > 0 ? ( - {infractions.map((infraction, index) => + {infractions.map(({ id }, index) => currentInfractionIndex !== undefined && index === currentInfractionIndex ? ( ) : ( ) )} diff --git a/frontend/src/features/missions/MissionForm/ActionForm/ControlForm/index.tsx b/frontend/src/features/missions/MissionForm/ActionForm/ControlForm/index.tsx index 98c8e8f9d..c1a02d9d7 100644 --- a/frontend/src/features/missions/MissionForm/ActionForm/ControlForm/index.tsx +++ b/frontend/src/features/missions/MissionForm/ActionForm/ControlForm/index.tsx @@ -1,23 +1,23 @@ import { actionFactory } from '@features/missions/Missions.helpers' import { useGetControlPlans } from '@hooks/useGetControlPlans' import { - customDayjs, - FormikNumberInput, - FormikTextarea, - MultiRadio, - getOptionsFromLabelledEnum, - type OptionValueType, + Accent, + Button, DatePicker, FieldError, - Accent, + FormikNumberInput, + FormikTextInput, + FormikTextarea, Icon, + MultiRadio, Size, THEME, Toggle, + customDayjs, + getOptionsFromLabelledEnum, pluralize, - Button, - FormikTextInput, - useNewWindow + useNewWindow, + type OptionValueType } from '@mtes-mct/monitor-ui' import { FieldArray, useFormikContext, type FormikErrors } from 'formik' import _ from 'lodash' @@ -29,10 +29,10 @@ import { MultiPointPicker } from './MultiPointPicker' import { OtherControlTypesForm } from './OtherControlTypesForm' import { CONTROL_PLAN_INIT, UNIQ_CONTROL_PLAN_INDEX } from '../../../../../domain/entities/controlPlan' import { - type Mission, - type EnvActionControl, ActionTypeEnum, - CompletionStatus + CompletionStatus, + type EnvActionControl, + type Mission } from '../../../../../domain/entities/missions' import { ReportingTargetTypeEnum, TargetTypeEnum, TargetTypeLabels } from '../../../../../domain/entities/targetType' import { VehicleTypeEnum } from '../../../../../domain/entities/vehicleType' @@ -44,25 +44,23 @@ import { useMissionAndActionsCompletion } from '../../hooks/useMissionAndActions import { Separator } from '../../style' import { MissingFieldsText } from '../MissingFieldsText' import { + ActionFormBody, ActionThemes, ActionTitle, - ActionFormBody, Header, HeaderButtons, + StyledAuthorContainer, StyledDeleteIconButton, - TitleWithIcon, - StyledAuthorContainer + TitleWithIcon } from '../style' import { ActionTheme } from '../Themes/ActionTheme' export function ControlForm({ currentActionId, - removeControlAction, - setCurrentActionId + removeControlAction }: { currentActionId: string removeControlAction: () => void - setCurrentActionId: (actionId: string | undefined) => void }) { const { newWindowContainerRef } = useNewWindow() const { @@ -170,7 +168,6 @@ export function ControlForm({ } const handleRemoveAction = () => { - setCurrentActionId(undefined) removeControlAction() } diff --git a/frontend/src/features/missions/MissionForm/ActionForm/NoteForm.tsx b/frontend/src/features/missions/MissionForm/ActionForm/NoteForm.tsx index c62f29f50..f81696f58 100644 --- a/frontend/src/features/missions/MissionForm/ActionForm/NoteForm.tsx +++ b/frontend/src/features/missions/MissionForm/ActionForm/NoteForm.tsx @@ -7,7 +7,7 @@ import { Header, HeaderButtons, StyledDeleteIconButton, TitleWithIcon } from './ import { type EnvAction, type EnvActionNote, type Mission } from '../../../../domain/entities/missions' import { FormTitle, Separator } from '../style' -export function NoteForm({ currentActionId, remove, setCurrentActionId }) { +export function NoteForm({ currentActionId, remove }) { const [actionsFields] = useField('envActions') const { setFieldValue, @@ -17,7 +17,6 @@ export function NoteForm({ currentActionId, remove, setCurrentActionId }) { const currentAction = envActions[envActionIndex] const handleRemoveAction = () => { - setCurrentActionId(undefined) remove(currentActionId) } diff --git a/frontend/src/features/missions/MissionForm/ActionForm/ReportingForm/index.tsx b/frontend/src/features/missions/MissionForm/ActionForm/ReportingForm/index.tsx index c0a28e419..34a61c93a 100644 --- a/frontend/src/features/missions/MissionForm/ActionForm/ReportingForm/index.tsx +++ b/frontend/src/features/missions/MissionForm/ActionForm/ReportingForm/index.tsx @@ -24,10 +24,10 @@ const EMPTY_VALUE = '--' export function ReportingForm({ reportingActionIndex, - setCurrentActionId: setCurrentActionIndex + setCurrentActionId }: { reportingActionIndex: number - setCurrentActionId: (string) => void + setCurrentActionId: (actionId: string | undefined) => void }) { const dispatch = useAppDispatch() const { subThemes, themes } = useGetControlPlans() @@ -77,8 +77,7 @@ export function ReportingForm({ }) setFieldValue('envActions', envActionsToUpdate) setFieldValue('detachedReportingIds', [...(values.detachedReportingIds ?? []), reporting.id]) - - setCurrentActionIndex(undefined) + setCurrentActionId(undefined) } return ( diff --git a/frontend/src/features/missions/MissionForm/ActionForm/SurveillanceForm/index.tsx b/frontend/src/features/missions/MissionForm/ActionForm/SurveillanceForm/index.tsx index 583a32006..a2a2960dd 100644 --- a/frontend/src/features/missions/MissionForm/ActionForm/SurveillanceForm/index.tsx +++ b/frontend/src/features/missions/MissionForm/ActionForm/SurveillanceForm/index.tsx @@ -50,7 +50,7 @@ import { } from '../style' import { SurveillanceThemes } from '../Themes/SurveillanceThemes' -export function SurveillanceForm({ currentActionId, remove, setCurrentActionId }) { +export function SurveillanceForm({ currentActionId, remove }) { const { newWindowContainerRef } = useNewWindow() const { @@ -146,7 +146,6 @@ export function SurveillanceForm({ currentActionId, remove, setCurrentActionId } ) const handleRemoveAction = () => { - setCurrentActionId(undefined) remove(envActionIndex) } diff --git a/frontend/src/features/missions/MissionForm/ActionForm/index.tsx b/frontend/src/features/missions/MissionForm/ActionForm/index.tsx index b8310fa63..3a8e13be5 100644 --- a/frontend/src/features/missions/MissionForm/ActionForm/index.tsx +++ b/frontend/src/features/missions/MissionForm/ActionForm/index.tsx @@ -17,8 +17,9 @@ type ActionFormProps = { export function ActionForm({ currentActionId, setCurrentActionId }: ActionFormProps) { const [attachedReportingsField] = useField('attachedReportings') const reportingActionIndex = (attachedReportingsField.value ?? []).findIndex( - reporting => String(reporting.id) === currentActionId + reporting => reporting.id === currentActionId ) + const [reportingField] = useField(`attachedReportings.${reportingActionIndex}`) const [envActionsField, , envActionsHelper] = useField('envActions') @@ -32,7 +33,7 @@ export function ActionForm({ currentActionId, setCurrentActionId }: ActionFormPr envActionsHelper.setValue(actionsToUpdate) setCurrentActionId(undefined) - }, [envActionIndex, envActionsField, envActionsHelper, setCurrentActionId]) + }, [envActionIndex, envActionsField.value, envActionsHelper, setCurrentActionId]) if (currentActionId === undefined) { return ( @@ -62,30 +63,19 @@ export function ActionForm({ currentActionId, setCurrentActionId }: ActionFormPr key={actionIdField.value} currentActionId={currentActionId} removeControlAction={removeAction} - setCurrentActionId={setCurrentActionId} /> ) case ActionTypeEnum.SURVEILLANCE: return ( - + ) case ActionTypeEnum.NOTE: return ( - + ) diff --git a/frontend/src/features/missions/MissionForm/ActionsTimeLine/index.tsx b/frontend/src/features/missions/MissionForm/ActionsTimeLine/index.tsx index 29df57ad0..79950573f 100644 --- a/frontend/src/features/missions/MissionForm/ActionsTimeLine/index.tsx +++ b/frontend/src/features/missions/MissionForm/ActionsTimeLine/index.tsx @@ -95,13 +95,14 @@ export function ActionsTimeLine({ currentActionId, setCurrentActionId }) { const handleSelectAction = useCallback( id => { - setCurrentActionId(actions && Object.keys(actions).find(key => key === String(id))) + setCurrentActionId(id) }, - [actions, setCurrentActionId] + [setCurrentActionId] ) const handleRemoveAction = useCallback( - id => { + (id, event) => { + event.stopPropagation() if (!envActions) { return } @@ -111,8 +112,9 @@ export function ActionsTimeLine({ currentActionId, setCurrentActionId }) { const actionsToUpdate = [...(envActions || [])] actionsToUpdate.splice(actionToDeleteIndex, 1) setFieldValue('envActions', actionsToUpdate) + + setCurrentActionId(undefined) } - setCurrentActionId(undefined) }, [envActions, setCurrentActionId, setFieldValue] ) @@ -174,9 +176,9 @@ export function ActionsTimeLine({ currentActionId, setCurrentActionId }) { action={action} duplicateAction={() => handleDuplicateAction(action.id)} hasError={!!envActionsErrors} - removeAction={() => handleRemoveAction(action.id)} + removeAction={event => handleRemoveAction(action.id, event)} selectAction={() => handleSelectAction(action.id)} - selected={String(action.id) === currentActionId} + selected={action.id === currentActionId} setCurrentActionId={setCurrentActionId} /> ) diff --git a/frontend/src/features/missions/MissionForm/hooks/useSyncFormValuesWithRedux.ts b/frontend/src/features/missions/MissionForm/hooks/useSyncFormValuesWithRedux.ts index d69b4b8ed..bba1b8614 100644 --- a/frontend/src/features/missions/MissionForm/hooks/useSyncFormValuesWithRedux.ts +++ b/frontend/src/features/missions/MissionForm/hooks/useSyncFormValuesWithRedux.ts @@ -19,9 +19,6 @@ export function useSyncFormValuesWithRedux(isAutoSaveEnabled: boolean) { const engagedControlUnit = useAppSelector(state => activeMissionId ? state.missionForms.missions[activeMissionId]?.engagedControlUnit : undefined ) - const activeActionId = useAppSelector(state => - activeMissionId ? state.missionForms.missions[activeMissionId]?.activeActionId : undefined - ) const dispatchFormUpdate = useDebouncedCallback(async (newValues: Mission) => { if (!newValues || newValues.id !== activeMissionId) { @@ -31,7 +28,11 @@ export function useSyncFormValuesWithRedux(isAutoSaveEnabled: boolean) { const isFormDirty = isMissionFormDirty() dispatch( - missionFormsActions.setMission({ activeActionId, engagedControlUnit, isFormDirty, missionForm: newValues }) + missionFormsActions.setMission({ + engagedControlUnit, + isFormDirty, + missionForm: newValues + }) ) }, 350) diff --git a/frontend/src/features/missions/MissionForm/index.tsx b/frontend/src/features/missions/MissionForm/index.tsx index 5c6a6748f..33985c4e1 100644 --- a/frontend/src/features/missions/MissionForm/index.tsx +++ b/frontend/src/features/missions/MissionForm/index.tsx @@ -18,13 +18,9 @@ export function MissionFormWrapper() { const selectedMission = useAppSelector(state => activeMissionId ? state.missionForms.missions[activeMissionId] : undefined ) - const engagedControlUnit = useAppSelector(state => - activeMissionId ? state.missionForms.missions[activeMissionId]?.engagedControlUnit : undefined - ) + const engagedControlUnit = selectedMission?.engagedControlUnit - const activeActionId = useAppSelector(state => - activeMissionId ? state.missionForms.missions[activeMissionId]?.activeActionId : undefined - ) + const activeAction = selectedMission?.activeAction const missionIsNewMission = useMemo(() => isNewMission(activeMissionId), [activeMissionId]) @@ -74,7 +70,7 @@ export function MissionFormWrapper() { >
) { + if (state.activeMissionId) { + const activeMission = state.missions[state.activeMissionId] + if (activeMission) { + activeMission.activeAction = { + ...activeMission.activeAction, + activeInfractionId: action.payload + } } } }, + setActiveMissionId(state, action: PayloadAction) { state.activeMissionId = action.payload }, @@ -96,7 +116,7 @@ const missionFormsSlice = createSlice({ } const mission = state.missions[id] if (mission) { - state.missions[id] = action.payload + state.missions[id] = { ...mission, ...action.payload } } else { state.missions = { ...state.missions, [id]: action.payload } }