Skip to content

Commit

Permalink
Show env actions in timeline and in refactor mission overlay
Browse files Browse the repository at this point in the history
  • Loading branch information
louptheron committed Apr 8, 2024
1 parent 5a016b5 commit a57150c
Show file tree
Hide file tree
Showing 17 changed files with 170 additions and 218 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package fr.gouv.cnsp.monitorfish.infrastructure.api.bff

import fr.gouv.cnsp.monitorfish.domain.use_cases.mission.GetAllMissions
import fr.gouv.cnsp.monitorfish.domain.use_cases.mission.GetMission
import fr.gouv.cnsp.monitorfish.infrastructure.api.outputs.FullMissionWithActionsDataOutput
import fr.gouv.cnsp.monitorfish.infrastructure.api.outputs.MissionWithActionsDataOutput
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
Expand Down Expand Up @@ -70,11 +69,11 @@ class MissionController(
@PathParam("Id")
@PathVariable(name = "id")
id: Int,
): FullMissionWithActionsDataOutput {
): MissionWithActionsDataOutput {
return runBlocking {
val missionAndActions = getMission.execute(id)

return@runBlocking FullMissionWithActionsDataOutput.fromMissionAndActions(missionAndActions)
return@runBlocking MissionWithActionsDataOutput.fromMissionAndActions(missionAndActions)
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fr.gouv.cnsp.monitorfish.infrastructure.api.outputs

import fr.gouv.cnsp.monitorfish.domain.entities.mission.*
import fr.gouv.cnsp.monitorfish.domain.entities.mission.env_mission_action.EnvMissionAction
import java.time.ZonedDateTime

/**
Expand All @@ -16,6 +17,9 @@ data class MissionWithActionsDataOutput(
val observationsCnsp: String? = null,
val facade: String? = null,
val geom: MultiPolygon? = null,
val createdAtUtc: ZonedDateTime? = null,
val updatedAtUtc: ZonedDateTime? = null,
val envActions: List<EnvMissionAction>? = listOf(),
val startDateTimeUtc: ZonedDateTime,
val endDateTimeUtc: ZonedDateTime? = null,
val isGeometryComputedFromControls: Boolean,
Expand All @@ -36,6 +40,9 @@ data class MissionWithActionsDataOutput(
observationsCnsp = missionAndActions.mission.observationsCnsp,
facade = missionAndActions.mission.facade,
geom = missionAndActions.mission.geom,
createdAtUtc = missionAndActions.mission.createdAtUtc,
updatedAtUtc = missionAndActions.mission.updatedAtUtc,
envActions = missionAndActions.mission.envActions,
startDateTimeUtc = missionAndActions.mission.startDateTimeUtc,
endDateTimeUtc = missionAndActions.mission.endDateTimeUtc,
isGeometryComputedFromControls = missionAndActions.mission.isGeometryComputedFromControls,
Expand Down
28 changes: 27 additions & 1 deletion frontend/src/domain/entities/mission/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { getMissionActionInfractionsFromMissionActionFormValues } from '@features/Mission/components/MissionForm/ActionList/utils'
import { getMissionCompletionFrontStatus } from '@features/Mission/components/MissionForm/utils'
import { EnvMissionAction } from '@features/Mission/envMissionAction.types'
import { Mission } from '@features/Mission/mission.types'
import { MissionAction } from '@features/Mission/missionAction.types'
import { isLandControl } from '@features/Mission/useCases/getLastControlCircleGeometry'
Expand Down Expand Up @@ -32,6 +34,7 @@ export function getMissionFeaturePointId(id: number) {

export const getMissionFeaturePoint = ({
actions,
envActions,
...mission
}: Mission.MissionWithActions): Feature<Point> | undefined => {
const geoJSON = new GeoJSON()
Expand Down Expand Up @@ -59,12 +62,15 @@ export const getMissionFeaturePoint = ({
action.actionType === MissionActionType.SEA_CONTROL
).length
const numberOfSurveillance = actions.filter(action => action.actionType === MissionActionType.AIR_SURVEILLANCE).length
const actionsCompletion = actions.map(action => action.completion)

const feature = new Feature({
color: getMissionColor(missionStatus),
controlUnits: mission.controlUnits,
endDateTimeUtc: mission.endDateTimeUtc,
geometry: new Point(point),
hasEnvActions: envActions.length > 0,
hasFishActions: actions.length > 0,
isAirMission: mission.missionTypes.length === 1 && mission.missionTypes.includes(MissionType.AIR),
isClosed: booleanToInt(missionStatus === MissionStatus.CLOSED),
isDone: booleanToInt(missionStatus === MissionStatus.DONE),
Expand All @@ -73,8 +79,9 @@ export const getMissionFeaturePoint = ({
isMultiMission: mission.missionTypes.length > 1,
isSeaMission: mission.missionTypes.length === 1 && mission.missionTypes.includes(MissionType.SEA),
isUpcoming: booleanToInt(missionStatus === MissionStatus.UPCOMING),
missionCompletion: getMissionCompletionFrontStatus(mission, actionsCompletion),
missionId: mission.id,
missionSource: mission.missionSource,
missionSources: getMissionSources(actions, envActions),
missionStatus,
missionTypes: mission.missionTypes,
numberOfControls,
Expand Down Expand Up @@ -183,3 +190,22 @@ export function getMissionSourceTagText(missionSource: MissionSource | undefined
return 'Origine inconnue'
}
}

function getMissionSources(
actions: MissionAction.MissionAction[],
envActions: EnvMissionAction.MissionAction[]
): MissionSource[] {
let sources: MissionSource[] = []

const hasMonitorFishActions = actions.length > 0
if (hasMonitorFishActions) {
sources = sources.concat(MissionSource.MONITORFISH)
}

const hasMonitorEnvActions = envActions.length > 0
if (hasMonitorEnvActions) {
sources = sources.concat(MissionSource.MONITORENV)
}

return sources
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import { getMissionCompletion, getMissionCompletionFrontStatus } from '@features/Mission/components/MissionForm/utils'
import { getMissionCompletionFrontStatus } from '@features/Mission/components/MissionForm/utils'
import { MissionAction } from '@features/Mission/missionAction.types'
import { useMainAppSelector } from '@hooks/useMainAppSelector'

import { getMissionStatus } from '../../../../../domain/entities/mission/utils'

import FrontCompletionStatus = MissionAction.FrontCompletionStatus

export function useGetMissionCompletion(): FrontCompletionStatus {
const draft = useMainAppSelector(state => state.missionForm.draft)
const completion = getMissionCompletion(draft)

if (!draft?.mainFormValues) {
return FrontCompletionStatus.TO_COMPLETE
}

const missionStatus = getMissionStatus(draft?.mainFormValues)
const actionsCompletion = draft?.actionsFormValues?.map(action => action.completion)

return getMissionCompletionFrontStatus(missionStatus, completion)
return getMissionCompletionFrontStatus(draft?.mainFormValues, actionsCompletion)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
useDeleteMissionActionMutation,
useUpdateMissionActionMutation
} from '@api/missionAction'
import { useGetMissionCompletion } from '@features/Mission/components/MissionForm/hooks/useGetMissionCompletion'
import { CompletionStatusTag } from '@features/Mission/components/MissionForm/shared/CompletionStatusTag'
import { Mission } from '@features/Mission/mission.types'
import { autoSaveMission } from '@features/Mission/useCases/autoSaveMission'
Expand Down Expand Up @@ -44,7 +45,7 @@ import { AutoSaveTag } from './shared/AutoSaveTag'
import { DeletionConfirmationDialog } from './shared/DeletionConfirmationDialog'
import { DraftCancellationConfirmationDialog } from './shared/DraftCancellationConfirmationDialog'
import { ExternalActionsDialog } from './shared/ExternalActionsDialog'
import { TitleStatusTag } from './shared/TitleStatusTag'
import { MissionStatusTag } from './shared/MissionStatusTag'
import { missionFormActions } from './slice'
import { getTitleFromMissionMainFormValues } from './utils'
import { areMissionFormsValuesValid } from './utils/areMissionFormsValuesValid'
Expand All @@ -69,6 +70,7 @@ export function MissionForm() {
const hasEngagedControlUnit = useMainAppSelector(state => !!state.missionForm.engagedControlUnit)
assertNotNullish(draft)

const completion = useGetMissionCompletion()
const missionIdRef = useRef<number | undefined>(missionIdFromPath)

const [, { isLoading: isCreatingMission }] = useCreateMissionMutation()
Expand Down Expand Up @@ -435,8 +437,8 @@ export function MissionForm() {
<BackToListIcon onClick={goToMissionList} />

<HeaderTitle>{title}</HeaderTitle>
{mainFormValues && <TitleStatusTag status={getMissionStatus(mainFormValues)} />}
<CompletionStatusTag />
{mainFormValues && <MissionStatusTag status={getMissionStatus(mainFormValues)} />}
<CompletionStatusTag completion={completion} />
</Header>

<Body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { useGetMissionCompletion } from '@features/Mission/components/MissionForm/hooks/useGetMissionCompletion'
import { MissionAction } from '@features/Mission/missionAction.types'
import { ExclamationPoint, Icon, Tag, THEME } from '@mtes-mct/monitor-ui'
import styled from 'styled-components'

import FrontCompletionStatus = MissionAction.FrontCompletionStatus

export function CompletionStatusTag() {
const completion = useGetMissionCompletion()
if (!completion) {
return null
}

type CompletionStatusTagProps = {
completion: FrontCompletionStatus
}
export function CompletionStatusTag({ completion }: CompletionStatusTagProps) {
switch (completion) {
case FrontCompletionStatus.COMPLETED:
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,48 @@ import styled from 'styled-components'

import MissionStatus = Mission.MissionStatus

type TitleStatusTagProps = Readonly<{
type MissionStatusTagProps = Readonly<{
status: MissionStatus | undefined
}>
export function TitleStatusTag({ status }: TitleStatusTagProps) {
export function MissionStatusTag({ status }: MissionStatusTagProps) {
switch (status) {
case Mission.MissionStatus.UPCOMING:
return (
<MissionStatusTag accent={Accent.PRIMARY} Icon={Icon.Clock} iconColor={THEME.color.blueNcs}>
<StyledTag accent={Accent.PRIMARY} Icon={Icon.Clock} iconColor={THEME.color.blueNcs}>
{Mission.MissionStatusLabel.UPCOMING}
</MissionStatusTag>
</StyledTag>
)
case Mission.MissionStatus.IN_PROGRESS:
return (
<MissionStatusTag
<StyledTag
accent={Accent.PRIMARY}
color={THEME.color.charcoal}
Icon={Icon.Clock}
iconColor={THEME.color.blueGray}
>
{Mission.MissionStatusLabel.IN_PROGRESS}
</MissionStatusTag>
</StyledTag>
)
// TODO: remove this line when the CLOSED status is removed
case Mission.MissionStatus.CLOSED:
return (
<MissionStatusTag accent={Accent.PRIMARY} Icon={Icon.Confirm} iconColor={THEME.color.charcoal}>
<StyledTag accent={Accent.PRIMARY} Icon={Icon.Confirm} iconColor={THEME.color.charcoal}>
{Mission.MissionStatusLabel.CLOSED}
</MissionStatusTag>
</StyledTag>
)
case Mission.MissionStatus.DONE:
return (
<MissionStatusTag accent={Accent.PRIMARY} Icon={Icon.Confirm} iconColor={THEME.color.charcoal}>
<StyledTag accent={Accent.PRIMARY} Icon={Icon.Confirm} iconColor={THEME.color.charcoal}>
{Mission.MissionStatusLabel.DONE}
</MissionStatusTag>
</StyledTag>
)

default:
return null
}
}

const MissionStatusTag = styled(Tag)`
const StyledTag = styled(Tag)`
align-self: end;
padding: 1px 8px 3px 3px;
`
27 changes: 19 additions & 8 deletions frontend/src/features/Mission/components/MissionForm/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { validateRequiredFormValues } from '@utils/validateRequiredFormValues'
import { difference, omit } from 'lodash'

import { MISSION_ACTION_FORM_VALUES_SKELETON } from './constants'
import { getMissionStatus } from '../../../../domain/entities/mission/utils'
import { Mission } from '../../mission.types'
import { MissionAction } from '../../missionAction.types'

import type { MissionActionFormValues, MissionMainFormValues } from './types'
import type { MissionWithActionsDraft } from '@features/Mission/types'
import type { Undefine } from '@mtes-mct/monitor-ui'
import type { LegacyControlUnit } from 'domain/types/legacyControlUnit'

Expand Down Expand Up @@ -165,26 +165,37 @@ export function getValidMissionDataControlUnit(
return validMissionDataControlUnit
}

export function getMissionCompletion(draft: MissionWithActionsDraft | undefined): CompletionStatus {
if (!draft) {
export function getMissionCompletion(
mission: Partial<MissionMainFormValues> | Mission.Mission | undefined,
actionsCompletion: (CompletionStatus | undefined)[] | undefined
): CompletionStatus {
if (!mission || !actionsCompletion) {
return CompletionStatus.TO_COMPLETE
}

const hasAtLeastOnUncompletedAction = draft.actionsFormValues.find(
action => !action.completion || action.completion === CompletionStatus.TO_COMPLETE
const hasAtLeastOnUncompletedAction = actionsCompletion.find(
completion => !completion || completion === CompletionStatus.TO_COMPLETE
)

if (hasAtLeastOnUncompletedAction || !MainFormLiveSchema.isValidSync(draft.mainFormValues)) {
if (hasAtLeastOnUncompletedAction || !MainFormLiveSchema.isValidSync(mission)) {
return CompletionStatus.TO_COMPLETE
}

return CompletionStatus.COMPLETED
}

export function getMissionCompletionFrontStatus(
missionStatus: Mission.MissionStatus | undefined,
missionCompletion: CompletionStatus
mission: Partial<MissionMainFormValues> | Mission.Mission | undefined,
actionsCompletion: (CompletionStatus | undefined)[] | undefined
): FrontCompletionStatus {
const missionCompletion = getMissionCompletion(mission, actionsCompletion)

if (!mission) {
return FrontCompletionStatus.TO_COMPLETE
}

const missionStatus = getMissionStatus(mission)

if (missionStatus === Mission.MissionStatus.IN_PROGRESS && missionCompletion === CompletionStatus.COMPLETED) {
return FrontCompletionStatus.UP_TO_DATE
}
Expand Down
Loading

0 comments on commit a57150c

Please sign in to comment.