From cb48e4ef8339c941e4ba6b29f9c7207e579722d7 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 15 Jan 2025 16:44:44 +0100 Subject: [PATCH] feat(mission): compute status and complete for stats (front) - Service to get mission - hook to calculate status - hook to compute completeness for actions - add store's entries on timeline / general infos(completeness for stats) - add store's entries on mission (status/ isMissionFinished --- .../layout/mission-page-header-wrapper.tsx | 17 ++--- .../hooks/use-mission-report-export.tsx | 8 +-- .../common/hooks/use-mission-timeline.tsx | 5 +- .../common/hooks/use-mission-type.tsx | 24 ++++--- .../v2/features/common/hooks/use-mission.tsx | 52 +++++++++++++++ .../features/common/services/use-mission.tsx | 15 +++++ .../v2/features/common/types/mission-types.ts | 29 +++++++-- .../elements/mission-action-header-action.tsx | 6 +- .../elements/mission-action-item-control.tsx | 6 +- .../elements/mission-control-env-form.tsx | 1 - .../layout/mission-timeline-wrapper.tsx | 10 ++- .../hooks/use-timeline-complete-for-stats.tsx | 17 +++++ .../mission-timeline/hooks/use-timeline.tsx | 8 +-- .../components/element/mission-action-pam.tsx | 7 +- .../mission-list/mission-list-header-pam.tsx | 6 +- .../element/mission-action-item-ulam.tsx | 2 +- .../element/mission-action-ulam.tsx | 7 +- ...ssion-general-information-initial-form.tsx | 65 +++++++++---------- .../mission-list/mission-list-header-ulam.tsx | 4 +- frontend/src/v2/pages/mission-pam-page.tsx | 8 +-- frontend/src/v2/pages/mission-ulam-page.tsx | 10 +-- frontend/src/v2/store/index.ts | 22 ++++++- ...eneral-infos-complete-for-stats-reducer.ts | 14 ++++ .../src/v2/store/slices/mission-reducer.ts | 14 ++++ .../timeline-complete-for-stats-reducer.ts | 14 ++++ 25 files changed, 265 insertions(+), 106 deletions(-) create mode 100644 frontend/src/v2/features/common/hooks/use-mission.tsx create mode 100644 frontend/src/v2/features/common/services/use-mission.tsx create mode 100644 frontend/src/v2/features/mission-timeline/hooks/use-timeline-complete-for-stats.tsx create mode 100644 frontend/src/v2/store/slices/general-infos-complete-for-stats-reducer.ts create mode 100644 frontend/src/v2/store/slices/mission-reducer.ts create mode 100644 frontend/src/v2/store/slices/timeline-complete-for-stats-reducer.ts diff --git a/frontend/src/v2/features/common/components/layout/mission-page-header-wrapper.tsx b/frontend/src/v2/features/common/components/layout/mission-page-header-wrapper.tsx index 506ce017a..fa0cd0b4d 100644 --- a/frontend/src/v2/features/common/components/layout/mission-page-header-wrapper.tsx +++ b/frontend/src/v2/features/common/components/layout/mission-page-header-wrapper.tsx @@ -1,4 +1,4 @@ -import { CompletenessForStatsStatusEnum, Mission, MissionStatusEnum } from '@common/types/mission-types.ts' +import { MissionStatusEnum } from '@common/types/mission-types.ts' import Text from '@common/components/ui/text.tsx' import { Accent, Button, Icon, IconButton, Size, TagGroup, THEME } from '@mtes-mct/monitor-ui' @@ -7,6 +7,8 @@ import React from 'react' import { FlexboxGrid, Stack } from 'rsuite' import styled from 'styled-components' import { useDate } from '../../hooks/use-date.tsx' +import { useMission } from '../../hooks/use-mission.tsx' +import { Mission } from '../../types/mission-types.ts' import MissionCompletenessForStatsTag from '../elements/mission-completeness-for-stats-tag.tsx' import MissionSourceTag from '../elements/mission-source-tag.tsx' import MissionStatusTag from '../elements/mission-status-tag.tsx' @@ -37,7 +39,7 @@ const MissionPageHeaderWrapper: React.FC = ({ exportLoading }) => { const { formatMissionName } = useDate() - const exportRapportEnabled = mission?.completenessForStats?.status === CompletenessForStatsStatusEnum.COMPLETE + const { status, completeForStats, exportRapportEnabled } = useMission(mission) return ( <> @@ -54,11 +56,8 @@ const MissionPageHeaderWrapper: React.FC = ({ - - + + @@ -95,9 +94,7 @@ const MissionPageHeaderWrapper: React.FC = ({ - {mission?.status === MissionStatusEnum.ENDED && ( - - )} + {status === MissionStatusEnum.ENDED && } ) } diff --git a/frontend/src/v2/features/common/hooks/use-mission-report-export.tsx b/frontend/src/v2/features/common/hooks/use-mission-report-export.tsx index 93d3a6cdd..7815e58f9 100644 --- a/frontend/src/v2/features/common/hooks/use-mission-report-export.tsx +++ b/frontend/src/v2/features/common/hooks/use-mission-report-export.tsx @@ -4,18 +4,18 @@ import { MissionPatrolExportMutationArgs, useLazyExportMissionReports } from '../services/use-lazy-export-mission-reports.tsx' -import { BLOBTYPE, useDownloadFile } from './use-download-file.tsx' import { ExportMode } from '../types/mission-export-types.ts' +import { BLOBTYPE, useDownloadFile } from './use-download-file.tsx' interface ExportMissionHook { - loading: boolean + exportIsLoading: boolean exportMissionReport: (args: MissionPatrolExportMutationArgs) => Promise } export function useMissionReportExport(): ExportMissionHook { const { handleDownload } = useDownloadFile() const [getMissionReport] = useLazyExportMissionReports() - const [loading, setLoading] = useState(false) + const [exportIsLoading, setLoading] = useState(false) const exportMissionReport = async (args: MissionPatrolExportMutationArgs) => { setLoading(true) @@ -36,5 +36,5 @@ export function useMissionReportExport(): ExportMissionHook { } } - return { exportMissionReport, loading } + return { exportMissionReport, exportIsLoading } } diff --git a/frontend/src/v2/features/common/hooks/use-mission-timeline.tsx b/frontend/src/v2/features/common/hooks/use-mission-timeline.tsx index dd460c91d..b0b636ca9 100644 --- a/frontend/src/v2/features/common/hooks/use-mission-timeline.tsx +++ b/frontend/src/v2/features/common/hooks/use-mission-timeline.tsx @@ -1,9 +1,8 @@ import { ActionType } from '../types/action-type' import { MissionNavAction } from '../types/mission-action' -import { MissionSource } from '../types/mission-types' +import { MissionSourceEnum } from '../types/mission-types' type ActionRegistryInput = { [key in ActionType]?: unknown } -type Input = { missionId: number; startDateTimeUtc: Date } const ACTION_REGISTRY_INPUT: ActionRegistryInput = { [ActionType.NOTE]: { endDateTimeUtc: new Date().toISOString() }, @@ -19,7 +18,7 @@ export function useMissionTimeline(missionId?: number): TimelineHook { const input = { missionId: Number(missionId), actionType, - source: MissionSource.RAPPORTNAV, + source: MissionSourceEnum.RAPPORTNAV, data: { ...(moreData ?? {}), ...(ACTION_REGISTRY_INPUT[actionType] ?? {}), diff --git a/frontend/src/v2/features/common/hooks/use-mission-type.tsx b/frontend/src/v2/features/common/hooks/use-mission-type.tsx index de334b8ee..db55d9b6a 100644 --- a/frontend/src/v2/features/common/hooks/use-mission-type.tsx +++ b/frontend/src/v2/features/common/hooks/use-mission-type.tsx @@ -1,19 +1,18 @@ -import { MissionReinforcementTypeEnum, MissionReportTypeEnum, MissionTypeEnum } from '../types/mission-types.ts' - +import { MissionReinforcementTypeEnum, MissionReportTypeEnum, MissionType } from '../types/mission-types.ts' interface MissionHook { - getMissionTypeLabel: (type?: MissionTypeEnum) => string | undefined + getMissionTypeLabel: (type?: MissionType) => string | undefined getReinforcementTypeLabel: (type?: MissionReinforcementTypeEnum) => string | undefined getReportTypeLabel: (type?: MissionReportTypeEnum) => string | undefined - missionTypeOptions: { label: string; value: MissionTypeEnum }[] + missionTypeOptions: { label: string; value: MissionType }[] reinforcementTypeOptions: { label: string; value: MissionReinforcementTypeEnum }[] reportTypeOptions: { label: string; value: MissionReportTypeEnum }[] } -const MISSION_TYPE_REGISTRY: Record = { - [MissionTypeEnum.LAND]: 'Terre', - [MissionTypeEnum.SEA]: 'Mer', - [MissionTypeEnum.AIR]: 'Air' +const MISSION_TYPE_REGISTRY: Record = { + [MissionType.LAND]: 'Terre', + [MissionType.SEA]: 'Mer', + [MissionType.AIR]: 'Air' } const REINFORCEMENT_TYPE_REGISTRY: Record = { @@ -32,8 +31,7 @@ const REPORT_TYPE_REGISTRY: Record = { } export function useMissionType(): MissionHook { - const getMissionTypeLabel = (type?: MissionTypeEnum): string | undefined => - type ? MISSION_TYPE_REGISTRY[type] : '' + const getMissionTypeLabel = (type?: MissionType): string | undefined => (type ? MISSION_TYPE_REGISTRY[type] : '') const getReinforcementTypeLabel = (type?: MissionReinforcementTypeEnum): string | undefined => type ? REINFORCEMENT_TYPE_REGISTRY[type] : '' @@ -42,9 +40,9 @@ export function useMissionType(): MissionHook { type ? REPORT_TYPE_REGISTRY[type] : '' const getMissionTypeOptions = () => - Object.keys(MissionTypeEnum).map(key => ({ - value: MissionTypeEnum[key as keyof typeof MissionTypeEnum], - label: MISSION_TYPE_REGISTRY[key as keyof typeof MissionTypeEnum] + Object.keys(MissionType).map(key => ({ + value: MissionType[key as keyof typeof MissionType], + label: MISSION_TYPE_REGISTRY[key as keyof typeof MissionType] })) const getReinforcementTypeOptions = () => diff --git a/frontend/src/v2/features/common/hooks/use-mission.tsx b/frontend/src/v2/features/common/hooks/use-mission.tsx new file mode 100644 index 000000000..30a1e9ff9 --- /dev/null +++ b/frontend/src/v2/features/common/hooks/use-mission.tsx @@ -0,0 +1,52 @@ +import {} from '@common/types/env-mission-types' +import { CompletenessForStats, MissionStatusEnum } from '@common/types/mission-types' +import { useStore } from '@tanstack/react-store' +import { isAfter, isBefore, isSameDay, parseISO } from 'date-fns' +import { isNil } from 'lodash' +import { useEffect, useState } from 'react' +import { store } from '../../../store' +import { setMissionStatus } from '../../../store/slices/mission-reducer' +import { CompletenessForStatsStatusEnum, Mission } from '../types/mission-types' + +interface MissionHook { + status?: MissionStatusEnum + exportRapportEnabled: boolean + completeForStats?: CompletenessForStats +} + +export function useMission(mission?: Mission): MissionHook { + const [status, setStatus] = useState() + const [completeForStats, setCompleteForStats] = useState() + const timelieCompleteForStats = useStore(store, state => state.timeline.completnessForStats) + const exportRapportEnabled = completeForStats?.status === CompletenessForStatsStatusEnum.COMPLETE + + useEffect(() => { + if (!mission) return + const status = computeMissionStatus(mission.startDateTimeUtc, mission.endDateTimeUtc) + setStatus(status) + setMissionStatus(status) + }, [mission]) + + useEffect(() => { + setCompleteForStats({ + status: timelieCompleteForStats?.status, //TODO: compute with generalIformation + sources: timelieCompleteForStats?.sources ////TODO: compute with generalIformation + }) + }, [timelieCompleteForStats]) + + const computeMissionStatus = (startDate: string, endDate?: string) => { + const today = new Date() + if (isNil(endDate) || isNil(startDate)) return MissionStatusEnum.UNAVAILABLE + try { + if (isAfter(parseISO(endDate), today)) return MissionStatusEnum.IN_PROGRESS + if (isBefore(parseISO(endDate), today) || isSameDay(parseISO(endDate), today)) return MissionStatusEnum.ENDED + if (isAfter(parseISO(startDate), today) || isSameDay(parseISO(startDate), today)) + return MissionStatusEnum.UPCOMING + } catch (e) { + console.error(`calculateMissionStatus - error with startDate: ${startDate}, endDate: ${endDate}`, e) + } + return MissionStatusEnum.UNAVAILABLE + } + + return { status, completeForStats, exportRapportEnabled } +} diff --git a/frontend/src/v2/features/common/services/use-mission.tsx b/frontend/src/v2/features/common/services/use-mission.tsx new file mode 100644 index 000000000..097fe3652 --- /dev/null +++ b/frontend/src/v2/features/common/services/use-mission.tsx @@ -0,0 +1,15 @@ +import { skipToken, useQuery } from '@tanstack/react-query' +import axios from '../../../../query-client/axios' +import { Mission } from '../types/mission-types' + +const useGetMissionQuery = (missionId?: string) => { + const fetchMission = (): Promise => axios.get(`missions/${missionId}`).then(response => response.data) + + const query = useQuery({ + queryKey: ['mission', missionId], + queryFn: missionId ? fetchMission : skipToken + }) + return query +} + +export default useGetMissionQuery diff --git a/frontend/src/v2/features/common/types/mission-types.ts b/frontend/src/v2/features/common/types/mission-types.ts index 98514f448..5c4da2c8d 100644 --- a/frontend/src/v2/features/common/types/mission-types.ts +++ b/frontend/src/v2/features/common/types/mission-types.ts @@ -1,6 +1,6 @@ import { ControlUnit } from '@common/types/control-unit-types.ts' -export enum MissionTypeEnum { +export enum MissionType { AIR = 'AIR', LAND = 'LAND', SEA = 'SEA' @@ -9,7 +9,7 @@ export enum MissionTypeEnum { export type MissionULAMGeneralInfoInitial = { startDateTimeUtc: string endDateTimeUtc: string - missionTypes: MissionTypeEnum[] + missionTypes: MissionType[] missionReportType?: MissionReportTypeEnum reinforcementType?: MissionReinforcementTypeEnum nbHourAtSea?: number @@ -30,7 +30,7 @@ export enum MissionReinforcementTypeEnum { DIRM = 'DIRM' } -export enum MissionSource { +export enum MissionSourceEnum { MONITORENV = 'MONITORENV', MONITORFISH = 'MONITORFISH', POSEIDON_CACEM = 'POSEIDON_CACEM', @@ -38,9 +38,21 @@ export enum MissionSource { RAPPORTNAV = 'RAPPORTNAV' } -export type MissionEnv = { +export enum CompletenessForStatsStatusEnum { + COMPLETE = 'COMPLETE', + INCOMPLETE = 'INCOMPLETE' +} + +export enum MissionStatus { + UPCOMING = 'UPCOMING', + IN_PROGRESS = 'IN_PROGRESS', + ENDED = 'ENDED', + UNAVAILABLE = 'UNAVAILABLE' +} + +export type Mission = { id?: number - missionTypes: MissionTypeEnum[] + missionTypes: MissionType[] controlUnits: ControlUnit[] openBy?: string completedBy?: string @@ -50,8 +62,13 @@ export type MissionEnv = { geom?: string startDateTimeUtc: string endDateTimeUtc?: string - missionSource: MissionSource + missionSource: MissionSourceEnum hasMissionOrder: boolean isUnderJdp: boolean isGeometryComputedFromControls: boolean } + +export type CompletenessForStats = { + sources?: MissionSourceEnum[] + status?: CompletenessForStatsStatusEnum +} diff --git a/frontend/src/v2/features/mission-action/components/elements/mission-action-header-action.tsx b/frontend/src/v2/features/mission-action/components/elements/mission-action-header-action.tsx index f56aececa..814105bbc 100644 --- a/frontend/src/v2/features/mission-action/components/elements/mission-action-header-action.tsx +++ b/frontend/src/v2/features/mission-action/components/elements/mission-action-header-action.tsx @@ -2,12 +2,12 @@ import { Accent, Icon, IconButton, Size, THEME } from '@mtes-mct/monitor-ui' import { useNavigate } from 'react-router-dom' import { Stack } from 'rsuite' import useDeleteActionMutation from '../../../common/services/use-delete-mission-action' -import { MissionSource } from '../../../common/types/mission-types' +import { MissionSourceEnum } from '../../../common/types/mission-types' interface MissionActionHeaderActionProps { actionId: string missionId: number - source: MissionSource + source: MissionSourceEnum } export const MissionActionHeaderAction: React.FC = ({ @@ -23,7 +23,7 @@ export const MissionActionHeaderAction: React.FC navigate(`/v2/pam/missions/${missionId}`) } - const isDeleteDisabled = () => source !== MissionSource.RAPPORTNAV + const isDeleteDisabled = () => source !== MissionSourceEnum.RAPPORTNAV return ( diff --git a/frontend/src/v2/features/mission-action/components/elements/mission-action-item-control.tsx b/frontend/src/v2/features/mission-action/components/elements/mission-action-item-control.tsx index 07abf2418..6ba760e7b 100644 --- a/frontend/src/v2/features/mission-action/components/elements/mission-action-item-control.tsx +++ b/frontend/src/v2/features/mission-action/components/elements/mission-action-item-control.tsx @@ -1,6 +1,6 @@ import { FC } from 'react' import { MissionAction } from '../../../common/types/mission-action' -import { MissionSource } from '../../../common/types/mission-types' +import { MissionSourceEnum } from '../../../common/types/mission-types' import MissionActionItemEnvControl from './mission-action-item-env-control' import MissionActionItemFishControl from './mission-action-item-fish-control' import MissionActionItemNavControl from './mission-action-item-nav-control' @@ -11,9 +11,9 @@ const MissionActionItemControl: FC<{ isMissionFinished?: boolean }> = ({ action, onChange, isMissionFinished }) => { switch (action.source) { - case MissionSource.MONITORENV: + case MissionSourceEnum.MONITORENV: return - case MissionSource.MONITORFISH: + case MissionSourceEnum.MONITORFISH: return default: return diff --git a/frontend/src/v2/features/mission-control/components/elements/mission-control-env-form.tsx b/frontend/src/v2/features/mission-control/components/elements/mission-control-env-form.tsx index 7137ffd8d..674ce42f9 100644 --- a/frontend/src/v2/features/mission-control/components/elements/mission-control-env-form.tsx +++ b/frontend/src/v2/features/mission-control/components/elements/mission-control-env-form.tsx @@ -7,7 +7,6 @@ import { EnvControl, EnvControlInput, useEnvControl } from '../../hooks/use-cont import MissionControlEnvError from '../ui/mission-control-env-error.tsx' import { MissionControlTitle } from '../ui/mission-control-title.tsx' -const MAX_CONTROL = 1 export interface MissionControlEnvFormProps { name: string isToComplete?: boolean diff --git a/frontend/src/v2/features/mission-timeline/components/layout/mission-timeline-wrapper.tsx b/frontend/src/v2/features/mission-timeline/components/layout/mission-timeline-wrapper.tsx index ab5ac36cb..801b6a10f 100644 --- a/frontend/src/v2/features/mission-timeline/components/layout/mission-timeline-wrapper.tsx +++ b/frontend/src/v2/features/mission-timeline/components/layout/mission-timeline-wrapper.tsx @@ -1,8 +1,10 @@ import { THEME } from '@mtes-mct/monitor-ui' import { find } from 'lodash' -import { createElement, FC, Fragment, FunctionComponent } from 'react' +import { createElement, FC, Fragment, FunctionComponent, useEffect } from 'react' import { Divider, Stack } from 'rsuite' +import { setTimelineCompleteForStats } from '../../../../store/slices/timeline-complete-for-stats-reducer' import { useDate } from '../../../common/hooks/use-date' +import { useTimelineCompleteForStats } from '../../hooks/use-timeline-complete-for-stats' import { MissionTimelineAction } from '../../types/mission-timeline-output' import MissionTimelineEmpty from '../ui/mission-timeline-empty' import MissionTimelineError from '../ui/mission-timeline-error' @@ -26,6 +28,12 @@ const MissionTimelineWrapper: FC = ({ groupBy }) => { const { groupByDay } = useDate() + const { computeCompleteForStats } = useTimelineCompleteForStats() + useEffect(() => { + const completenessForStats = computeCompleteForStats(actions) + setTimelineCompleteForStats(completenessForStats) + }, [actions]) + if (isLoading) return if (actions?.length === 0) return if (isError) return diff --git a/frontend/src/v2/features/mission-timeline/hooks/use-timeline-complete-for-stats.tsx b/frontend/src/v2/features/mission-timeline/hooks/use-timeline-complete-for-stats.tsx new file mode 100644 index 000000000..61f77045e --- /dev/null +++ b/frontend/src/v2/features/mission-timeline/hooks/use-timeline-complete-for-stats.tsx @@ -0,0 +1,17 @@ +import { CompletenessForStatsStatusEnum, MissionSourceEnum } from '../../common/types/mission-types' +import { MissionTimelineAction } from '../types/mission-timeline-output' + +export function useTimelineCompleteForStats() { + const computeCompleteForStats = (actions: MissionTimelineAction[]) => { + const sources = new Set() + + actions.forEach(action => { + if (!action.isCompleteForStats && action.source) sources.add(action.source) + }) + return { + sources: Array.from(sources), + status: sources.size === 0 ? CompletenessForStatsStatusEnum.COMPLETE : CompletenessForStatsStatusEnum.INCOMPLETE + } + } + return { computeCompleteForStats } +} diff --git a/frontend/src/v2/features/mission-timeline/hooks/use-timeline.tsx b/frontend/src/v2/features/mission-timeline/hooks/use-timeline.tsx index aafe59dc9..c3ee09eb8 100644 --- a/frontend/src/v2/features/mission-timeline/hooks/use-timeline.tsx +++ b/frontend/src/v2/features/mission-timeline/hooks/use-timeline.tsx @@ -3,7 +3,7 @@ import { IconProps } from '@mtes-mct/monitor-ui' import { FunctionComponent } from 'react' import { ActionGroupType, ActionType } from '../../common/types/action-type' import { MissionAction, MissionEnvAction, MissionFishAction, MissionNavAction } from '../../common/types/mission-action' -import { MissionSource } from '../../common/types/mission-types' +import { MissionSourceEnum } from '../../common/types/mission-types' import { MissionTimelineAction } from '../types/mission-timeline-output' export type TimeLineStyle = { @@ -52,11 +52,11 @@ export function useTimeline(): TimelineHook { return ( actions?.map(action => { switch (action.source) { - case MissionSource.RAPPORTNAV: + case MissionSourceEnum.RAPPORTNAV: return getTimeLineFromNavAction(action) - case MissionSource.MONITORENV: + case MissionSourceEnum.MONITORENV: return getTimeLineFromEnvAction(action) - case MissionSource.MONITORFISH: + case MissionSourceEnum.MONITORFISH: return getTimeLineFromFishAction(action) default: return {} as MissionTimelineAction diff --git a/frontend/src/v2/features/pam/components/element/mission-action-pam.tsx b/frontend/src/v2/features/pam/components/element/mission-action-pam.tsx index 4d5629ea5..c7a2fa154 100644 --- a/frontend/src/v2/features/pam/components/element/mission-action-pam.tsx +++ b/frontend/src/v2/features/pam/components/element/mission-action-pam.tsx @@ -1,5 +1,6 @@ -import { MissionStatusEnum } from '@common/types/mission-types' +import { useStore } from '@tanstack/react-store' import { FC } from 'react' +import { store } from '../../../../store' import MissionPageSectionWrapper from '../../../common/components/layout/mission-page-section-wrapper' import useGetActionQuery from '../../../common/services/use-mission-action' import MissionActionPamBody from './mission-action-pam-body' @@ -8,11 +9,11 @@ import MissionActionPamHeader from './mission-action-pam-header' interface MissionActionProps { actionId?: string missionId: number - status?: MissionStatusEnum } -const MissionActionPam: FC = ({ missionId, actionId, status }) => { +const MissionActionPam: FC = ({ missionId, actionId }) => { const query = useGetActionQuery(missionId, actionId) + const status = useStore(store, state => state.mission.status) return ( = ({}) => { +const MissionListHeaderPam: React.FC = () => { return ( diff --git a/frontend/src/v2/features/ulam/components/element/mission-action-item-ulam.tsx b/frontend/src/v2/features/ulam/components/element/mission-action-item-ulam.tsx index a5494e132..e06c7bf49 100644 --- a/frontend/src/v2/features/ulam/components/element/mission-action-item-ulam.tsx +++ b/frontend/src/v2/features/ulam/components/element/mission-action-item-ulam.tsx @@ -24,7 +24,7 @@ const MissionActionItemUlam: FC = ({ action, mission handleExecuteOnDelay(async () => { await mutation.mutateAsync(newAction) if (debounceTime !== undefined) resetDebounceTime() - }) + }, debounceTime) } return ( diff --git a/frontend/src/v2/features/ulam/components/element/mission-action-ulam.tsx b/frontend/src/v2/features/ulam/components/element/mission-action-ulam.tsx index d0d47afb0..f61e969cd 100644 --- a/frontend/src/v2/features/ulam/components/element/mission-action-ulam.tsx +++ b/frontend/src/v2/features/ulam/components/element/mission-action-ulam.tsx @@ -1,5 +1,6 @@ -import { MissionStatusEnum } from '@common/types/mission-types' +import { useStore } from '@tanstack/react-store' import { FC } from 'react' +import { store } from '../../../../store' import MissionPageSectionWrapper from '../../../common/components/layout/mission-page-section-wrapper' import useGetActionQuery from '../../../common/services/use-mission-action' import MissionActionUlamBody from './mission-action-ulam-body' @@ -8,11 +9,11 @@ import MissionActionUlamHeader from './mission-action-ulam-header' interface MissionActionProps { actionId?: string missionId: number - status?: MissionStatusEnum } -const MissionActionUlam: FC = ({ missionId, actionId, status }) => { +const MissionActionUlam: FC = ({ missionId, actionId }) => { const query = useGetActionQuery(missionId, actionId) + const status = useStore(store, state => state.mission.status) return ( void } -const MissionGeneralInformationInitialForm: FC = ({ name, fieldFormik, isCreation = false, onClose }) => { - +const MissionGeneralInformationInitialForm: FC = ({ + name, + fieldFormik, + isCreation = false, + onClose +}) => { const { initValue, handleSubmit } = useMissionGeneralInformationsForm(name, fieldFormik) - const { missionTypeOptions, reportTypeOptions, reinforcementTypeOptions} = useMissionType() + const { missionTypeOptions, reportTypeOptions, reinforcementTypeOptions } = useMissionType() return ( <> {initValue && ( {formik => ( - - - - + + + + - + {formik.values['missionReportType'] === MissionReportTypeEnum.EXTERNAL_REINFORCEMENT_TIME_REPORT && ( - + )} - + - + {!isCreation && ( - + )} - - {isCreation && ( - - - + )} @@ -98,7 +96,6 @@ const MissionGeneralInformationInitialForm: FC )} - ) } diff --git a/frontend/src/v2/features/ulam/components/element/mission-list/mission-list-header-ulam.tsx b/frontend/src/v2/features/ulam/components/element/mission-list/mission-list-header-ulam.tsx index 307ba39de..78faedc2c 100644 --- a/frontend/src/v2/features/ulam/components/element/mission-list/mission-list-header-ulam.tsx +++ b/frontend/src/v2/features/ulam/components/element/mission-list/mission-list-header-ulam.tsx @@ -1,10 +1,10 @@ +import { THEME } from '@mtes-mct/monitor-ui' import React from 'react' import { FlexboxGrid } from 'rsuite' -import { THEME } from '@mtes-mct/monitor-ui' interface MissionListHeaderProps {} -const MissionListHeaderUlam: React.FC = ({}) => { +const MissionListHeaderUlam: React.FC = () => { return ( diff --git a/frontend/src/v2/pages/mission-pam-page.tsx b/frontend/src/v2/pages/mission-pam-page.tsx index 132f4ffe0..f114f1158 100644 --- a/frontend/src/v2/pages/mission-pam-page.tsx +++ b/frontend/src/v2/pages/mission-pam-page.tsx @@ -13,7 +13,7 @@ import MissionGeneralInformationHeader from '../features/common/components/ui/mi import MissionPageError from '../features/common/components/ui/mission-page-error.tsx' import MissionPageLoading from '../features/common/components/ui/mission-page-loading.tsx' import { useMissionReportExport } from '../features/common/hooks/use-mission-report-export.tsx' -import { useMissionExcerptQuery } from '../features/common/services/use-mission-excerpt.tsx' +import useGetMissionQuery from '../features/common/services/use-mission.tsx' import MissionActionPam from '../features/pam/components/element/mission-action-pam.tsx' import MissionTimelineHeaderPam from '../features/pam/components/element/mission-timeline-header-pam.tsx' import MissionTimelinePam from '../features/pam/components/element/mission-timeline-pam.tsx' @@ -24,13 +24,13 @@ const MissionPamPage: React.FC = () => { const { navigateAndResetCache } = useAuth() const exitMission = async () => navigateAndResetCache(ULAM_V2_HOME_PATH) + const { data: mission, isLoading, error } = useGetMissionQuery(missionId) const { exportMission, exportIsLoading } = useMissionReportExport(missionId) - const { loading, error, data: mission } = useMissionExcerptQuery(missionId) const lastSyncText = lastSync ? formatTime(new Date(parseInt(lastSync!!, 10))) : undefined if (error) return - if (loading) return + if (isLoading) return return ( { sectionBody={} /> } - missionAction={} + missionAction={} missionFooter={} /> ) diff --git a/frontend/src/v2/pages/mission-ulam-page.tsx b/frontend/src/v2/pages/mission-ulam-page.tsx index 3b030517d..2bc056052 100644 --- a/frontend/src/v2/pages/mission-ulam-page.tsx +++ b/frontend/src/v2/pages/mission-ulam-page.tsx @@ -13,7 +13,7 @@ import MissionGeneralInformationHeader from '../features/common/components/ui/mi import MissionPageError from '../features/common/components/ui/mission-page-error.tsx' import MissionPageLoading from '../features/common/components/ui/mission-page-loading.tsx' import { useMissionReportExport } from '../features/common/hooks/use-mission-report-export.tsx' -import { useMissionExcerptQuery } from '../features/common/services/use-mission-excerpt.tsx' +import useGetMissionQuery from '../features/common/services/use-mission.tsx' import MissionActionUlam from '../features/ulam/components/element/mission-action-ulam.tsx' import MissionGeneralInformationUlam from '../features/ulam/components/element/mission-general-information-ulam.tsx' import MissionTimelineHeaderUlam from '../features/ulam/components/element/mission-timeline-header-ulam.tsx' @@ -25,13 +25,13 @@ const MissionUlamPage: React.FC = () => { const { navigateAndResetCache } = useAuth() const exitMission = async () => navigateAndResetCache(ULAM_V2_HOME_PATH) - const { exportMission, exportIsLoading } = useMissionReportExport(missionId) - const { loading, error, data: mission } = useMissionExcerptQuery(missionId) + const { exportMission, exportIsLoading } = useMissionReportExport() + const { data: mission, isLoading, error } = useGetMissionQuery(missionId) const lastSyncText = lastSync ? formatTime(new Date(parseInt(lastSync!!, 10))) : undefined if (error) return - if (loading) return + if (isLoading) return return ( { sectionBody={} /> } - missionAction={} + missionAction={} missionFooter={} /> ) diff --git a/frontend/src/v2/store/index.ts b/frontend/src/v2/store/index.ts index 8610f1855..becf7f498 100644 --- a/frontend/src/v2/store/index.ts +++ b/frontend/src/v2/store/index.ts @@ -1,12 +1,28 @@ +import { MissionStatusEnum } from '@common/types/mission-types' import { Store } from '@tanstack/store' +import { CompletenessForStats } from '../features/common/types/mission-types' export interface State { delayQuery: { debounceTime?: number } + timeline: { + isCompleteForStats?: boolean + completnessForStats?: CompletenessForStats + } + generalInformations: { + isCompleteForStats?: boolean + completnessForStats?: CompletenessForStats + } + mission: { + status?: MissionStatusEnum + isMissionFinished?: boolean + } } + export const store = new Store({ - delayQuery: { - debounceTime: undefined - } + delayQuery: {}, + timeline: {}, + generalInformations: {}, + mission: {} }) diff --git a/frontend/src/v2/store/slices/general-infos-complete-for-stats-reducer.ts b/frontend/src/v2/store/slices/general-infos-complete-for-stats-reducer.ts new file mode 100644 index 000000000..c292e9d8d --- /dev/null +++ b/frontend/src/v2/store/slices/general-infos-complete-for-stats-reducer.ts @@ -0,0 +1,14 @@ +import { store } from '..' +import { CompletenessForStats, CompletenessForStatsStatusEnum } from '../../features/common/types/mission-types' + +export const setTimelineCompleteForStats = (completeForStats: CompletenessForStats) => { + store.setState(state => { + return { + ...state, + generalInformations: { + completeForStats, + isCompleteForStats: completeForStats.status === CompletenessForStatsStatusEnum.COMPLETE + } + } + }) +} diff --git a/frontend/src/v2/store/slices/mission-reducer.ts b/frontend/src/v2/store/slices/mission-reducer.ts new file mode 100644 index 000000000..014008f31 --- /dev/null +++ b/frontend/src/v2/store/slices/mission-reducer.ts @@ -0,0 +1,14 @@ +import { MissionStatusEnum } from '@common/types/mission-types' +import { store } from '..' + +export const setMissionStatus = (status: MissionStatusEnum) => { + store.setState(state => { + return { + ...state, + mission: { + status, + isMissionFinished: status === MissionStatusEnum.ENDED + } + } + }) +} diff --git a/frontend/src/v2/store/slices/timeline-complete-for-stats-reducer.ts b/frontend/src/v2/store/slices/timeline-complete-for-stats-reducer.ts new file mode 100644 index 000000000..5cfdba15e --- /dev/null +++ b/frontend/src/v2/store/slices/timeline-complete-for-stats-reducer.ts @@ -0,0 +1,14 @@ +import { store } from '..' +import { CompletenessForStats, CompletenessForStatsStatusEnum } from '../../features/common/types/mission-types' + +export const setTimelineCompleteForStats = (completeForStats: CompletenessForStats) => { + store.setState(state => { + return { + ...state, + timeline: { + completeForStats, + isCompleteForStats: completeForStats.status === CompletenessForStatsStatusEnum.COMPLETE + } + } + }) +}