diff --git a/frontend/src/features/common/types/mission-types.ts b/frontend/src/features/common/types/mission-types.ts index c8c6df5b0..c952491c7 100644 --- a/frontend/src/features/common/types/mission-types.ts +++ b/frontend/src/features/common/types/mission-types.ts @@ -72,3 +72,7 @@ export enum CompletenessForStatsStatusEnum { COMPLETE = 'COMPLETE', INCOMPLETE = 'INCOMPLETE' } + + + + diff --git a/frontend/src/v2/features/common/hooks/use-mission-general-informations-form.tsx b/frontend/src/v2/features/common/hooks/use-mission-general-informations-form.tsx new file mode 100644 index 000000000..4f602bd5b --- /dev/null +++ b/frontend/src/v2/features/common/hooks/use-mission-general-informations-form.tsx @@ -0,0 +1,50 @@ +import { FieldProps } from 'formik' +import { useAbstractFormikSubForm } from './use-abstract-formik-sub-form.tsx' +import { MissionULAMGeneralInfoInitial } from '../types/mission-types.ts' +import { useDate } from './use-date.tsx' + +export type MissionULAMGeneralInfoInitialInput = MissionULAMGeneralInfoInitial +export function useMissionGeneralInformationsForm( + name: string, + fieldFormik: FieldProps +) { + + const { preprocessDateForPicker, postprocessDateFromPicker } = useDate() + + + const fromFieldValueToInput = (data: MissionULAMGeneralInfoInitial) => { + return { + ...data, + dates: [ + preprocessDateForPicker(data.startDateTimeUtc), + preprocessDateForPicker(data.endDateTimeUtc) + ] + } + } + + + const fromInputToFieldValue = (value: MissionULAMGeneralInfoInitialInput): MissionULAMGeneralInfoInitial => { + const { dates, missionReportType, missionType, reinforcementType, nbHourAtSea } = value + return { + startDateTimeUtc: postprocessDateFromPicker(dates[0]), + endDateTimeUtc: postprocessDateFromPicker(dates[1]), + missionType, + missionReportType, + reinforcementType, + nbHourAtSea + } + } + + const { initValue, handleSubmit } = useAbstractFormikSubForm( + name, + fieldFormik, + fromFieldValueToInput, + fromInputToFieldValue + ) + + + return { + initValue, + handleSubmit, + } +} diff --git a/frontend/src/v2/features/common/hooks/use-mission-type.tsx b/frontend/src/v2/features/common/hooks/use-mission-type.tsx new file mode 100644 index 000000000..de334b8ee --- /dev/null +++ b/frontend/src/v2/features/common/hooks/use-mission-type.tsx @@ -0,0 +1,70 @@ +import { MissionReinforcementTypeEnum, MissionReportTypeEnum, MissionTypeEnum } from '../types/mission-types.ts' + + +interface MissionHook { + getMissionTypeLabel: (type?: MissionTypeEnum) => string | undefined + getReinforcementTypeLabel: (type?: MissionReinforcementTypeEnum) => string | undefined + getReportTypeLabel: (type?: MissionReportTypeEnum) => string | undefined + missionTypeOptions: { label: string; value: MissionTypeEnum }[] + 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 REINFORCEMENT_TYPE_REGISTRY: Record = { + [MissionReinforcementTypeEnum.PATROL]: 'Patrouille (mission PAM)', + [MissionReinforcementTypeEnum.JDP]: 'JDP', + [MissionReinforcementTypeEnum.DIRM]: 'DIRM', + [MissionReinforcementTypeEnum.OTHER_ULAM]: 'Autre ULAM', + [MissionReinforcementTypeEnum.SEA_TRAINER]: 'Formateur ESP Mer', + [MissionReinforcementTypeEnum.OTHER]: 'Autre' +} + +const REPORT_TYPE_REGISTRY: Record = { + [MissionReportTypeEnum.FIELD_REPORT]: 'Rapport avec sortie terrain', + [MissionReportTypeEnum.OFFICE_REPORT]: 'Rapport sans sortie terrain (admin. uniquement)', + [MissionReportTypeEnum.EXTERNAL_REINFORCEMENT_TIME_REPORT]: 'Rapport de temps agent en renfort extérieur' +} + +export function useMissionType(): MissionHook { + const getMissionTypeLabel = (type?: MissionTypeEnum): string | undefined => + type ? MISSION_TYPE_REGISTRY[type] : '' + + const getReinforcementTypeLabel = (type?: MissionReinforcementTypeEnum): string | undefined => + type ? REINFORCEMENT_TYPE_REGISTRY[type] : '' + + const getReportTypeLabel = (type?: MissionReportTypeEnum): string | undefined => + 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] + })) + + const getReinforcementTypeOptions = () => + Object.keys(MissionReinforcementTypeEnum).map(key => ({ + value: MissionReinforcementTypeEnum[key as keyof typeof MissionReinforcementTypeEnum], + label: REINFORCEMENT_TYPE_REGISTRY[key as keyof typeof MissionReinforcementTypeEnum] + })) + + const getReportTypeOptions = () => + Object.keys(MissionReportTypeEnum).map(key => ({ + value: MissionReportTypeEnum[key as keyof typeof MissionReportTypeEnum], + label: REPORT_TYPE_REGISTRY[key as keyof typeof MissionReportTypeEnum] + })) + + return { + getMissionTypeLabel, + getReinforcementTypeLabel, + getReportTypeLabel, + missionTypeOptions: getMissionTypeOptions(), + reinforcementTypeOptions: getReinforcementTypeOptions(), + reportTypeOptions: getReportTypeOptions() + } +} diff --git a/frontend/src/v2/features/common/types/mission-types.ts b/frontend/src/v2/features/common/types/mission-types.ts new file mode 100644 index 000000000..126a5eaec --- /dev/null +++ b/frontend/src/v2/features/common/types/mission-types.ts @@ -0,0 +1,33 @@ +export enum MissionTypeEnum { + AIR = 'AIR', + LAND = 'LAND', + SEA = 'SEA' +} + +export type MissionULAMGeneralInfoInitial = { + startDateTimeUtc: string + endDateTimeUtc: string + missionTypes: MissionTypeEnum[] + missionReportType?: MissionReportTypeEnum + reinforcementType?: MissionReinforcementTypeEnum + nbHourAtSea?: number +} + +export enum MissionReportTypeEnum { + FIELD_REPORT = 'FIELD_REPORT', + OFFICE_REPORT = 'OFFICE_REPORT', + EXTERNAL_REINFORCEMENT_TIME_REPORT = 'EXTERNAL_REINFORCEMENT_TIME_REPORT' +} + +export enum MissionReinforcementTypeEnum { + PATROL = 'PATROL', + JDP = 'JDP', + OTHER_ULAM = 'OTHER_ULAM', + SEA_TRAINER = 'SEA_TRAINER', + OTHER = 'OTHER', + DIRM = 'DIRM' +} + + + + diff --git a/frontend/src/v2/features/ulam/components/element/__tests__/mission-create-dialog.test.tsx b/frontend/src/v2/features/ulam/components/element/__tests__/mission-create-dialog.test.tsx new file mode 100644 index 000000000..fdc566d3a --- /dev/null +++ b/frontend/src/v2/features/ulam/components/element/__tests__/mission-create-dialog.test.tsx @@ -0,0 +1,23 @@ +import { render, screen, fireEvent } from '../../../../../../test-utils.tsx' +import { describe, it, vi } from 'vitest' +import MissionCreateDialog from '../mission-create-dialog.tsx' + +describe('MissionCreateDialog', () => { + it('renders the dialog when isOpen is true', () => { + render() + expect(screen.getByText("Création d'un rapport de mission")).toBeInTheDocument() + }) + + it('does not render the dialog when isOpen is false', () => { + render() + expect(screen.queryByText("Création d'un rapport de mission")).not.toBeInTheDocument() + }) + + it('calls onClose when the close button is clicked', () => { + const handleClose = vi.fn() + render() + + fireEvent.click(screen.getByText('Annuler')) + expect(handleClose).toHaveBeenCalled() + }) +}) diff --git a/frontend/src/v2/features/ulam/components/element/__tests__/mission-general-information-ulam-form-new.test.tsx b/frontend/src/v2/features/ulam/components/element/__tests__/mission-general-information-ulam-form-new.test.tsx new file mode 100644 index 000000000..5d8b7dd21 --- /dev/null +++ b/frontend/src/v2/features/ulam/components/element/__tests__/mission-general-information-ulam-form-new.test.tsx @@ -0,0 +1,35 @@ + +import { MissionTypeEnum } from '@common/types/env-mission-types' +import MissionGeneralInformationUlamFormNew from '../mission-general-information-ulam-form-new.tsx' +import { render, fireEvent, screen } from '../../../../../../test-utils.tsx' + + + +describe('MissionGeneralInformationUlamFormNew', () => { + it('renders the form with initial values', () => { + render( + + ) + + expect(screen.getByText('Type de mission')).toBeInTheDocument() + }) + + it('check if form submitted', () => { + const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); + + render( + + ); + + fireEvent.click(screen.getByText('Créer le rapport')); + + // TODO: a remplacer par le check d'un appel api + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Form Submitted'), expect.any(Object)); + + consoleSpy.mockRestore(); + }); +}) diff --git a/frontend/src/v2/features/ulam/components/element/mission-create-dialog.tsx b/frontend/src/v2/features/ulam/components/element/mission-create-dialog.tsx new file mode 100644 index 000000000..f2999871b --- /dev/null +++ b/frontend/src/v2/features/ulam/components/element/mission-create-dialog.tsx @@ -0,0 +1,43 @@ +import React, { FC, useEffect, useState } from 'react' +import { Dialog, THEME } from '@mtes-mct/monitor-ui' +import { Stack } from 'rsuite' +import { MissionTypeEnum } from '@common/types/env-mission-types.ts' +import MissionGeneralInformationUlamFormNew from './mission-general-information-ulam-form-new.tsx' + +interface MissionCreateDialogProps { + isOpen: boolean + onClose: () => void +} + +const MissionCreateDialog: FC = ({isOpen, onClose}) => { + + const [isDialogOpen, setIsDialogOpen] = useState(isOpen) + + useEffect(() => { + setIsDialogOpen(isOpen) + }, [isOpen]) + + + const handleClose = () => { + setIsDialogOpen(false) + onClose() + } + + + return ( + isDialogOpen && ( + + Création d'un rapport de mission + + + + + + + ) + ) +} + +export default MissionCreateDialog diff --git a/frontend/src/v2/features/ulam/components/element/mission-general-information-initial-form.tsx b/frontend/src/v2/features/ulam/components/element/mission-general-information-initial-form.tsx new file mode 100644 index 000000000..c6df22a63 --- /dev/null +++ b/frontend/src/v2/features/ulam/components/element/mission-general-information-initial-form.tsx @@ -0,0 +1,104 @@ +import React, { FC } from 'react' +import { FlexboxGrid, Stack } from 'rsuite' +import { + Accent, + Button, + FormikDateRangePicker, + FormikMultiCheckbox, + FormikNumberInput, + FormikSelect +} from '@mtes-mct/monitor-ui' +import { useMissionGeneralInformationsForm } from '../../../common/hooks/use-mission-general-informations-form.tsx' +import { FieldProps, Formik } from 'formik' +import { useMissionType } from '../../../common/hooks/use-mission-type.tsx' +import { MissionReportTypeEnum, MissionULAMGeneralInfoInitial } from '../../../common/types/mission-types.ts' + +export interface MissionGeneralInformationInitialFormProps { + name: string + fieldFormik: FieldProps + isCreation?: boolean + onClose?: () => void +} + +const MissionGeneralInformationInitialForm: FC = ({ name, fieldFormik, isCreation = false, onClose }) => { + + const { initValue, handleSubmit } = useMissionGeneralInformationsForm(name, fieldFormik) + const { missionTypeOptions, reportTypeOptions, reinforcementTypeOptions} = useMissionType() + + return ( + <> + {initValue && ( + + {formik => ( + + + + + + + + + + {formik.values['missionReportType'] === MissionReportTypeEnum.EXTERNAL_REINFORCEMENT_TIME_REPORT && ( + + + + )} + + + + + + + + {!isCreation && ( + + + + )} + + + + + + {isCreation && ( + + + + + + )} + + )} + + )} + + + ) +} + +export default MissionGeneralInformationInitialForm diff --git a/frontend/src/v2/features/ulam/components/element/mission-general-information-ulam-form-new.tsx b/frontend/src/v2/features/ulam/components/element/mission-general-information-ulam-form-new.tsx new file mode 100644 index 000000000..6adb2b99c --- /dev/null +++ b/frontend/src/v2/features/ulam/components/element/mission-general-information-ulam-form-new.tsx @@ -0,0 +1,70 @@ +import React from 'react' +import { MissionTypeEnum } from '@common/types/env-mission-types.ts' +import { Field, FieldProps, Formik } from 'formik' +import MissionGeneralInformationInitialForm from './mission-general-information-initial-form.tsx' +import { FormikEffect } from '@mtes-mct/monitor-ui' +import { + MissionReinforcementTypeEnum, MissionReportTypeEnum, MissionULAMGeneralInfoInitial +} from '../../../common/types/mission-types.ts' + +type NewMissionUlamGeneralInfoInitial = { missionGeneralInfo: MissionULAMGeneralInfoInitial } + +export interface MissionGeneralInformationUlamProps { + startDateTimeUtc?: string + endDateTimeUtc?: string + missionTypes?: MissionTypeEnum[] + missionReportType?: MissionReportTypeEnum + reinforcementType?: MissionReinforcementTypeEnum + nbHourAtSea?: number + onClose?: () => void +} + +const MissionGeneralInformationUlamFormNew: React.FC = ({ startDateTimeUtc, endDateTimeUtc, missionTypes, missionReportType, reinforcementType, nbHourAtSea, onClose }) => { + + const initialValues: MissionULAMGeneralInfoInitial = { + missionGeneralInfo : { + startDateTimeUtc, + endDateTimeUtc, + missionTypes, + reinforcementType, + missionReportType, + nbHourAtSea + } + } + + + const handleSubmit = (values) => { + if ( + values?.missionGeneralInfo?.missionReportType !== MissionReportTypeEnum.EXTERNAL_REINFORCEMENT_TIME_REPORT + ) { + values.missionGeneralInfo = values.missionGeneralInfo || {} + values.missionGeneralInfo.reinforcementType = null; + } + console.log('Form Submitted:', values); + }; + + + return ( + <> + + <> + handleSubmit(newValues as NewMissionUlamGeneralInfoInitial)} /> + + {(field: FieldProps) => ( + + )} + + + + + + + ) +} + +export default MissionGeneralInformationUlamFormNew diff --git a/frontend/src/v2/features/ulam/components/element/mission-list-ulam.tsx b/frontend/src/v2/features/ulam/components/element/mission-list-ulam.tsx index ca01a528e..537d7be0f 100644 --- a/frontend/src/v2/features/ulam/components/element/mission-list-ulam.tsx +++ b/frontend/src/v2/features/ulam/components/element/mission-list-ulam.tsx @@ -1,13 +1,23 @@ -import React, { JSX } from 'react' -import { Link, useNavigate } from 'react-router-dom' -import { Col, Container, FlexboxGrid, Loader, Stack } from 'rsuite' -import { Icon } from '@mtes-mct/monitor-ui' -interface MissionListUlamProps { - dateRangeNavigator: JSX.Element, +import React, { JSX, useState } from 'react' +import { useNavigate } from 'react-router-dom' +import { Col, Container, FlexboxGrid } from 'rsuite' +import { Accent, Button, Icon } from '@mtes-mct/monitor-ui' +import MissionCreateDialog from './mission-create-dialog.tsx' + +interface MissionListUlamProps { + dateRangeNavigator: JSX.Element missionListing: JSX.Element } -const MissionListUlam: React.FC = ({dateRangeNavigator, missionListing}) => { + +const MissionListUlam: React.FC = ({ dateRangeNavigator, missionListing }) => { const navigate = useNavigate() + + const [isDialogOpen, setIsDialogOpen] = useState(false) + + const handleCloseDialog = () => { + setIsDialogOpen(false) + } + return ( <> = ({dateRangeNavigator, mi > -

Missions

-

Mes rapports de mission

+ + +

+ Missions +

+

Mes rapports de mission

+
+ + + +
+ +
{dateRangeNavigator}