From 4c27f5fbed39a8a1c97170eb68c434cd92e5e342 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 7 Feb 2025 17:26:08 +0100 Subject: [PATCH 01/35] feat(user): api get user infos - UserRestController - UserRestController Test - UserInfos class --- .../api/bff/model/v2/UserInfos.kt | 10 ++++ .../api/bff/v2/UserRestController.kt | 50 +++++++++++++++++ .../bff/controllers/UserRestControllerTest.kt | 53 +++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/UserInfos.kt create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/UserRestController.kt create mode 100644 backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/infrastructure/bff/controllers/UserRestControllerTest.kt diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/UserInfos.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/UserInfos.kt new file mode 100644 index 00000000..be95825a --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/UserInfos.kt @@ -0,0 +1,10 @@ +package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2 + +data class UserInfos( + val id: Int, + val email: String, + val firstName: String? = null, + val lastName: String? = null, + val serviceId: Int? = null, + val serviceName: String? = null +) diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/UserRestController.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/UserRestController.kt new file mode 100644 index 00000000..4ef55bf6 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/UserRestController.kt @@ -0,0 +1,50 @@ +package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.v2 + +import fr.gouv.dgampa.rapportnav.domain.use_cases.service.GetServiceById +import fr.gouv.dgampa.rapportnav.domain.use_cases.user.FindById +import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.UserInfos +import org.slf4j.LoggerFactory +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("/api/v2/users") +class UserRestController( + private val findById: FindById, + private val getSeviceById: GetServiceById +) { + + private val logger = LoggerFactory.getLogger(UserRestController::class.java) + + /** + * Retrieves a specific user date by its ID. + * + * This endpoint fetches a user identified by the provided `userId` path variable. If the user exists, it + * returns the user data transformed into the API response format. If the user does not exist or an error occurs, + * it returns null. + * + * @param userId The unique identifier of the user to retrieve. + * @return The user data as a `UserInfos` object, or null if not found or an error occurs. + */ + @GetMapping("{userId}") + fun getUserById( + @PathVariable(name = "userId") userId: Int + ): UserInfos? { + try { + val user = this.findById.execute(userId) ?: return null + val service = this.getSeviceById.execute(userId) + return UserInfos( + id = user.id!!, + email = user.email, + firstName = user.firstName, + lastName = user.lastName, + serviceId = service?.id, + serviceName = service?.name, + ) + } catch (e: Exception) { + logger.error("Error while getting user information : ", e) + return null + } + } + + +} diff --git a/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/infrastructure/bff/controllers/UserRestControllerTest.kt b/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/infrastructure/bff/controllers/UserRestControllerTest.kt new file mode 100644 index 00000000..df437b30 --- /dev/null +++ b/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/infrastructure/bff/controllers/UserRestControllerTest.kt @@ -0,0 +1,53 @@ +package fr.gouv.gmampa.rapportnav.infrastructure.bff.controllers + +import fr.gouv.dgampa.rapportnav.RapportNavApplication +import fr.gouv.dgampa.rapportnav.domain.entities.mission.nav.ServiceEntity +import fr.gouv.dgampa.rapportnav.domain.use_cases.service.GetServiceById +import fr.gouv.dgampa.rapportnav.domain.use_cases.user.FindById +import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.v2.UserRestController +import fr.gouv.gmampa.rapportnav.mocks.user.UserMock +import org.junit.jupiter.api.Test +import org.mockito.ArgumentMatchers.any +import org.mockito.Mockito.`when` +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.bean.override.mockito.MockitoBean +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get + +@AutoConfigureMockMvc(addFilters = false) +@ContextConfiguration(classes = [RapportNavApplication::class]) +@WebMvcTest(UserRestController::class) +class UserRestControllerTest { + + @Autowired + private lateinit var mockMvc: MockMvc + + @MockitoBean + private lateinit var findById: FindById + + @MockitoBean + private lateinit var getSeviceById: GetServiceById + + @Test + fun `should return a user infor`() { + val user = UserMock.create() + val service = ServiceEntity( id = 1, name = "PAM Jeanne Barret A") + + `when`(findById.execute(id = 1)).thenReturn(user) + `when`(getSeviceById.execute(any())).thenReturn(service) + + // Act & Assert + mockMvc.perform( + get("/api/v2/users/1") + ) + .andExpect(status().isOk) + .andExpect(jsonPath("$.id").value(user.id)) + .andExpect(jsonPath("$.serviceName").value(service.name)) + } + +} From e51de9dbc5ad7a53cbbc3d9379f06dd54bb65e5f Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 7 Feb 2025 17:49:00 +0100 Subject: [PATCH 02/35] feat(user): front user infos - Get User infos and display --- frontend/src/v2/features/auth/hooks/use-auth.tsx | 8 ++++---- .../src/v2/features/common/services/use-user.tsx | 16 ++++++++++++++++ frontend/src/v2/features/common/types/user.ts | 11 +++++------ ...e-mission-action-generic-date-observation.tsx | 1 - frontend/src/v2/pages/mission-list-pam-page.tsx | 4 +++- frontend/src/v2/pages/mission-list-ulam-page.tsx | 6 +++++- 6 files changed, 33 insertions(+), 13 deletions(-) create mode 100644 frontend/src/v2/features/common/services/use-user.tsx diff --git a/frontend/src/v2/features/auth/hooks/use-auth.tsx b/frontend/src/v2/features/auth/hooks/use-auth.tsx index fc3a82be..40e1ba7c 100644 --- a/frontend/src/v2/features/auth/hooks/use-auth.tsx +++ b/frontend/src/v2/features/auth/hooks/use-auth.tsx @@ -1,16 +1,16 @@ import { useApolloClient } from '@apollo/client' import AuthToken from '@features/auth/utils/token' -import { jwtDecode } from 'jwt-decode' +import { jwtDecode, JwtPayload } from 'jwt-decode' import { useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' -import { User } from '../../common/types/user' type AuthHook = { isAuthenticated: boolean logout: () => Promise - isLoggedIn: () => User | undefined + isLoggedIn: () => Token | undefined navigateAndResetCache: (to: string) => Promise } +export type Token = JwtPayload & { userId: number } const authToken = new AuthToken() const useAuth = (): AuthHook => { @@ -41,7 +41,7 @@ const useAuth = (): AuthHook => { navigate(to) } - const isLoggedIn = (): User | undefined => { + const isLoggedIn = (): Token | undefined => { const token = authToken?.get() return token ? jwtDecode(token) : undefined } diff --git a/frontend/src/v2/features/common/services/use-user.tsx b/frontend/src/v2/features/common/services/use-user.tsx new file mode 100644 index 00000000..a023b3be --- /dev/null +++ b/frontend/src/v2/features/common/services/use-user.tsx @@ -0,0 +1,16 @@ +import { useQuery } from '@tanstack/react-query' +import axios from '../../../../query-client/axios' +import { User } from '../types/user' + +const useGetUserQuery = (userId?: number) => { + const fetchUser = (): Promise => axios.get(`users/${userId}`).then(response => response.data) + + const query = useQuery({ + queryKey: ['user', userId], + enabled: !!userId, + queryFn: fetchUser + }) + return query +} + +export default useGetUserQuery diff --git a/frontend/src/v2/features/common/types/user.ts b/frontend/src/v2/features/common/types/user.ts index ef298032..2512aabe 100644 --- a/frontend/src/v2/features/common/types/user.ts +++ b/frontend/src/v2/features/common/types/user.ts @@ -1,9 +1,8 @@ -import { RoleType } from './role-type' - export type User = { - id: string - name: string + id: number email: string - token: string - roles: RoleType[] + firstName?: string + lastName?: string + serviceId?: number + serviceName?: string } diff --git a/frontend/src/v2/features/mission-action/hooks/use-mission-action-generic-date-observation.tsx b/frontend/src/v2/features/mission-action/hooks/use-mission-action-generic-date-observation.tsx index 73b35743..e7cec44a 100644 --- a/frontend/src/v2/features/mission-action/hooks/use-mission-action-generic-date-observation.tsx +++ b/frontend/src/v2/features/mission-action/hooks/use-mission-action-generic-date-observation.tsx @@ -32,7 +32,6 @@ export function useMissionActionGenericDateObservation( ) const onSubmit = async (valueToSubmit?: MissionActionData) => { - debugger if (!valueToSubmit) return await onChange({ ...action, data: valueToSubmit }) } diff --git a/frontend/src/v2/pages/mission-list-pam-page.tsx b/frontend/src/v2/pages/mission-list-pam-page.tsx index 69016a4f..221b7060 100644 --- a/frontend/src/v2/pages/mission-list-pam-page.tsx +++ b/frontend/src/v2/pages/mission-list-pam-page.tsx @@ -3,6 +3,7 @@ import { Icon } from '@mtes-mct/monitor-ui' import { endOfYear } from 'date-fns/endOfYear' import { startOfYear } from 'date-fns/startOfYear' import { FC, useState } from 'react' +import useAuth from '../features/auth/hooks/use-auth.tsx' import MissionListDateRangeNavigator from '../features/common/components/elements/mission-list-daterange-navigator.tsx' import MissionListPageContentWrapper from '../features/common/components/layout/mission-list-page-content-wrapper.tsx' import MissionListPageHeaderWrapper from '../features/common/components/layout/mission-list-page-header-wrapper' @@ -28,6 +29,7 @@ const SIDEBAR_ITEMS = [ const MissionListPamPage: FC = () => { const today = new Date() + const { isLoggedIn } = useAuth() const [queryParams, setQueryParams] = useState({ startDateTimeUtc: startOfYear(today.toISOString()), endDateTimeUtc: endOfYear(today).toISOString() @@ -86,7 +88,7 @@ const MissionListPamPage: FC = () => { return ( } />} + header={} />} sidebar={} footer={<>} > diff --git a/frontend/src/v2/pages/mission-list-ulam-page.tsx b/frontend/src/v2/pages/mission-list-ulam-page.tsx index a511aeea..d7820bc6 100644 --- a/frontend/src/v2/pages/mission-list-ulam-page.tsx +++ b/frontend/src/v2/pages/mission-list-ulam-page.tsx @@ -3,6 +3,7 @@ import { Accent, Button, Icon } from '@mtes-mct/monitor-ui' import { endOfMonth, startOfMonth } from 'date-fns' import React, { useState } from 'react' import { Stack } from 'rsuite' +import useAuth from '../features/auth/hooks/use-auth.tsx' import MissionListDateRangeNavigator from '../features/common/components/elements/mission-list-daterange-navigator.tsx' import MissionListPageContentWrapper from '../features/common/components/layout/mission-list-page-content-wrapper.tsx' import MissionListPageHeaderWrapper from '../features/common/components/layout/mission-list-page-header-wrapper' @@ -26,6 +27,7 @@ const SIDEBAR_ITEMS = [ const MissionListUlamPage: React.FC = () => { const today = new Date() + const { isLoggedIn } = useAuth() const [queryParams, setQueryParams] = useState({ startDateTimeUtc: startOfMonth(today).toISOString(), endDateTimeUtc: endOfMonth(today).toISOString() @@ -56,9 +58,11 @@ const MissionListUlamPage: React.FC = () => { }) } + console.log(isLoggedIn()) + return ( } />} + header={} />} sidebar={} footer={<>} > From 04fd1d2d1b8dbe466108f70e00cb47e5e3c0da4b Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 7 Feb 2025 17:51:08 +0100 Subject: [PATCH 03/35] feat(userInfos): Page title --- .../layout/mission-list-page-title.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/frontend/src/v2/features/common/components/layout/mission-list-page-title.tsx b/frontend/src/v2/features/common/components/layout/mission-list-page-title.tsx index 68391ffc..2925ee57 100644 --- a/frontend/src/v2/features/common/components/layout/mission-list-page-title.tsx +++ b/frontend/src/v2/features/common/components/layout/mission-list-page-title.tsx @@ -1,7 +1,23 @@ +import { THEME } from '@mtes-mct/monitor-ui' import React from 'react' +import { Stack } from 'rsuite' +import useGetUserQuery from '../../services/use-user' -const MissionListPageTitle: React.FC = () => { - return

Rapport Nav

+type MissionListPageTitleProps = { + userId?: number +} + +const MissionListPageTitle: React.FC = ({ userId }) => { + const { data: user } = useGetUserQuery(userId) + return ( + + +

Rapport Nav

+
+ {user &&

}
+ {user &&

{user?.serviceName}

}
+
+ ) } export default MissionListPageTitle From f5ce9bf118c602c44cff61ef209ef047cc3e5155 Mon Sep 17 00:00:00 2001 From: aleckvincent Date: Mon, 3 Feb 2025 10:32:04 +0100 Subject: [PATCH 04/35] set MissionCrew#role as nullable and add rest controllers for crew --- .../mission/nav/crew/MissionCrewEntity.kt | 2 +- .../mission/crew/DeleteMissionCrew.kt | 5 ++- .../mission/crew/GetAgentsCrewByMissionId.kt | 2 +- .../export/ExportMissionRapportPatrouille.kt | 2 +- .../export/v2/ExportMissionPatrolSingle.kt | 2 +- .../api/bff/model/crew/Agent.kt | 8 ++++ .../api/bff/model/crew/MissionCrew.kt | 14 ++++++- .../api/bff/v2/AgentRestController.kt | 37 +++++++++++++++++++ .../api/bff/v2/AgentRoleController.kt | 19 ++++++++++ .../api/bff/v2/CrewRestController.kt | 3 ++ .../model/mission/crew/MissionCrewModel.kt | 8 ++-- .../mission/crew/JPAMissionCrewRepository.kt | 2 +- ...10.29__alter_missioncrew_role_not_null.sql | 7 ++++ .../crew/GetAgentsCrewByMissionIdTest.kt | 2 +- 14 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/AgentRestController.kt create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/AgentRoleController.kt create mode 100644 backend/src/main/resources/db/migration/V1.2025.02.03.10.29__alter_missioncrew_role_not_null.sql diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/nav/crew/MissionCrewEntity.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/nav/crew/MissionCrewEntity.kt index 252c9d6d..b253e9d3 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/nav/crew/MissionCrewEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/nav/crew/MissionCrewEntity.kt @@ -6,6 +6,6 @@ data class MissionCrewEntity( val id: Int? = null, val agent: AgentEntity, val comment: String? = null, - val role: AgentRoleEntity, + val role: AgentRoleEntity?, val missionId: Int, ) diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/crew/DeleteMissionCrew.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/crew/DeleteMissionCrew.kt index f0e289db..a35d0bef 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/crew/DeleteMissionCrew.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/crew/DeleteMissionCrew.kt @@ -2,16 +2,19 @@ package fr.gouv.dgampa.rapportnav.domain.use_cases.mission.crew import fr.gouv.dgampa.rapportnav.config.UseCase import fr.gouv.dgampa.rapportnav.domain.repositories.mission.crew.IMissionCrewRepository +import org.slf4j.LoggerFactory @UseCase data class DeleteMissionCrew(private val crewRepository: IMissionCrewRepository) { + private val logger = LoggerFactory.getLogger(DeleteMissionCrew::class.java) + fun execute(id: Int): Boolean { return try { crewRepository.deleteById(id = id) } catch (e: NoSuchElementException) { - // TODO add log + logger.error("DeleteMissionCrew : ${e.message}") return false } } diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/crew/GetAgentsCrewByMissionId.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/crew/GetAgentsCrewByMissionId.kt index e2ea2678..2f157465 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/crew/GetAgentsCrewByMissionId.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/crew/GetAgentsCrewByMissionId.kt @@ -27,6 +27,6 @@ class GetAgentsCrewByMissionId(private val agentCrewRepository: IMissionCrewRepo return agentCrewRepository.findByMissionId(missionId = missionId) .map { it.toMissionCrewEntity(commentDefaultsToString) } - .sortedBy { rolePriority.indexOf(it.role.title) } + .sortedBy { rolePriority.indexOf(it.role?.title) } } } diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/export/ExportMissionRapportPatrouille.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/export/ExportMissionRapportPatrouille.kt index 2cc0107b..844909a9 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/export/ExportMissionRapportPatrouille.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/export/ExportMissionRapportPatrouille.kt @@ -127,7 +127,7 @@ class ExportMissionRapportPatrouille( listOf("Fonction", "Nom", "Observation (formation, repos, mission, stage...)") ) + agentsCrew.map { listOf( - it.role.title, + it.role?.title, "${it.agent.firstName} ${it.agent.lastName}", it.comment.takeIf { comment -> !comment.isNullOrEmpty() } ?: "Présent" ) diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/export/v2/ExportMissionPatrolSingle.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/export/v2/ExportMissionPatrolSingle.kt index 3ae16929..06e80127 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/export/v2/ExportMissionPatrolSingle.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/export/v2/ExportMissionPatrolSingle.kt @@ -135,7 +135,7 @@ class ExportMissionPatrolSingle( listOf("Fonction", "Nom", "Observation (formation, repos, mission, stage...)") ) + agentsCrew.map { listOf( - it.role.title, + it.role?.title, "${it.agent.firstName} ${it.agent.lastName}", it.comment.takeIf { comment -> !comment.isNullOrEmpty() } ?: "Présent" ) diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/crew/Agent.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/crew/Agent.kt index 4914123f..589d83f5 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/crew/Agent.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/crew/Agent.kt @@ -16,4 +16,12 @@ data class Agent( ) } } + + fun toAgentEntity(): AgentEntity { + return AgentEntity( + id = id, + firstName = firstName, + lastName = lastName, + ) + } } diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/crew/MissionCrew.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/crew/MissionCrew.kt index 04dcefce..0d283320 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/crew/MissionCrew.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/crew/MissionCrew.kt @@ -7,7 +7,7 @@ data class MissionCrew( val agent: Agent, val missionId: Int, val comment: String?, - val role: AgentRole + val role: AgentRole? ) { companion object { @@ -16,10 +16,20 @@ data class MissionCrew( id = crew.id, missionId = crew.missionId, agent = Agent.fromAgentEntity(crew.agent), - role = AgentRole.fromAgentRoleEntity(crew.role), + role = crew.role?.let { AgentRole.fromAgentRoleEntity(it) }, comment = crew.comment ) } } + fun toMissionCrewEntity(): MissionCrewEntity { + return MissionCrewEntity( + id = id, + agent = agent.toAgentEntity(), + missionId = missionId, + comment = comment, + role = role?.toAgentRoleEntity() + ) + } + } diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/AgentRestController.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/AgentRestController.kt new file mode 100644 index 00000000..47f9e09b --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/AgentRestController.kt @@ -0,0 +1,37 @@ +package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.v2 + +import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.crew.GetAgents +import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.crew.GetAgentsByServiceId +import fr.gouv.dgampa.rapportnav.domain.use_cases.user.GetUserFromToken +import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.crew.Agent +import org.slf4j.LoggerFactory +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/api/v2/agents") +class AgentRestController( + private val getAgents: GetAgents, + private val getUserFromToken: GetUserFromToken, + private val getAgentsByServiceId: GetAgentsByServiceId, +) { + + private val logger = LoggerFactory.getLogger(AgentRestController::class.java) + + @GetMapping + fun agents(): List? { + return try { + val user = getUserFromToken.execute() + + user?.serviceId?.let { serviceId -> + val agents = getAgentsByServiceId.execute(serviceId) + .map { Agent.fromAgentEntity(it) } + agents + } + } catch (e: Exception) { + logger.error("[ERROR] API on endpoint agentsByServiceId:", e) + null + } + } +} diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/AgentRoleController.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/AgentRoleController.kt new file mode 100644 index 00000000..20a220fa --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/AgentRoleController.kt @@ -0,0 +1,19 @@ +package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.v2 + +import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.crew.GetAgentRoles +import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.crew.AgentRole +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/api/v2/agent_roles") +class AgentRoleController( + private val getAgentRoles: GetAgentRoles +) { + + @GetMapping("") + fun agentRoles(): List { + return getAgentRoles.execute().map { AgentRole.fromAgentRoleEntity(it) } + } +} diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/CrewRestController.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/CrewRestController.kt index 83d147eb..2b1b2fcc 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/CrewRestController.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/CrewRestController.kt @@ -1,5 +1,8 @@ package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.v2 +import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.crew.AddOrUpdateMissionCrew +import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.crew.DeleteMissionCrew +import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.crew.MissionCrew import fr.gouv.dgampa.rapportnav.domain.use_cases.service.GetCrewByServiceId import fr.gouv.dgampa.rapportnav.domain.use_cases.service.GetServices import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.crew.ServiceWithAgents diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/model/mission/crew/MissionCrewModel.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/model/mission/crew/MissionCrewModel.kt index f89cf89c..3eceec71 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/model/mission/crew/MissionCrewModel.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/model/mission/crew/MissionCrewModel.kt @@ -22,8 +22,8 @@ class MissionCrewModel( var comment: String? = null, @ManyToOne - @JoinColumn(name = "agent_role_id") - var role: AgentRoleModel, + @JoinColumn(name = "agent_role_id", nullable = true) + var role: AgentRoleModel?, ) { @@ -33,7 +33,7 @@ class MissionCrewModel( id = id, missionId = missionId, agent = agent.toAgentEntity(), - role = role.toAgentRoleEntity(), + role = role?.toAgentRoleEntity(), comment = if (comment == null && commentDefaultsToString == true) "" else comment ) } @@ -45,7 +45,7 @@ class MissionCrewModel( id = crew.id, missionId = crew.missionId, agent = AgentModel.fromAgentEntity(crew.agent), - role = AgentRoleModel.fromAgentRoleEntity(crew.role), + role = crew.role?.let { AgentRoleModel.fromAgentRoleEntity(it) }, comment = crew.comment ) } diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/repositories/mission/crew/JPAMissionCrewRepository.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/repositories/mission/crew/JPAMissionCrewRepository.kt index 680d7761..153e68e8 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/repositories/mission/crew/JPAMissionCrewRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/repositories/mission/crew/JPAMissionCrewRepository.kt @@ -28,7 +28,7 @@ class JPAMissionCrewRepository( override fun save(crew: MissionCrewEntity): MissionCrewModel { return try { val agent = dbAgentRepository.findById(crew.agent.id!!).orElseThrow() - val role = dbAgentRoleRepository.findById(crew.role.id!!).orElseThrow() + val role = dbAgentRoleRepository.findById(crew.role?.id!!).orElseThrow() val crewModel = MissionCrewModel.fromMissionCrewEntity(crew) crewModel.agent = agent diff --git a/backend/src/main/resources/db/migration/V1.2025.02.03.10.29__alter_missioncrew_role_not_null.sql b/backend/src/main/resources/db/migration/V1.2025.02.03.10.29__alter_missioncrew_role_not_null.sql new file mode 100644 index 00000000..3a522909 --- /dev/null +++ b/backend/src/main/resources/db/migration/V1.2025.02.03.10.29__alter_missioncrew_role_not_null.sql @@ -0,0 +1,7 @@ +DO +$$ + BEGIN + ALTER TABLE mission_crew + ALTER COLUMN agent_role_id DROP NOT NULL; + END +$$; diff --git a/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/domain/use_cases/mission/crew/GetAgentsCrewByMissionIdTest.kt b/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/domain/use_cases/mission/crew/GetAgentsCrewByMissionIdTest.kt index 5f195af5..f8e615b6 100644 --- a/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/domain/use_cases/mission/crew/GetAgentsCrewByMissionIdTest.kt +++ b/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/domain/use_cases/mission/crew/GetAgentsCrewByMissionIdTest.kt @@ -84,6 +84,6 @@ class GetAgentsCrewByMissionIdTest { // Assert val expectedRoles = listOf("Commandant", "Second capitaine", "Chef mécanicien", "Cuisinier") - assertEquals(expectedRoles, sortedCrew.map { it.role.title }) + assertEquals(expectedRoles, sortedCrew.map { it.role?.title }) } } From 36140ecc1cfed45bbced800a72638521d25d8559 Mon Sep 17 00:00:00 2001 From: aleckvincent Date: Tue, 4 Feb 2025 11:37:48 +0100 Subject: [PATCH 05/35] improve add and delete crew for ulam --- .../layout/mission-page-header-wrapper.tsx | 4 +- .../services/use-add-multiple-crews.tsx | 22 +++ .../features/common/services/use-agents.tsx | 17 ++ .../common/services/use-delete-crew.tsx | 21 +++ .../services/use-mission-crews-by-mission.tsx | 17 ++ .../src/v2/features/common/types/crew-type.ts | 21 +++ .../v2/features/common/types/mission-types.ts | 13 +- .../components/element/mission-crew-ulam.tsx | 146 +++++++++++++++++ .../mission-crew/mission-crew-form.tsx | 148 ++++++++++++++++++ .../mission-crew/mission-crew-member-list.tsx | 86 ++++++++++ ...mission-general-information-final-form.tsx | 45 ++++++ ...ssion-general-information-initial-form.tsx | 58 +++---- ...sion-general-information-ulam-form-new.tsx | 4 +- .../mission-general-information-ulam.tsx | 94 +++++++++-- .../ulam/services/use-agent-roles.tsx | 19 +++ .../ulam/services/use-create-mission.tsx | 6 +- 16 files changed, 673 insertions(+), 48 deletions(-) create mode 100644 frontend/src/v2/features/common/services/use-add-multiple-crews.tsx create mode 100644 frontend/src/v2/features/common/services/use-agents.tsx create mode 100644 frontend/src/v2/features/common/services/use-delete-crew.tsx create mode 100644 frontend/src/v2/features/common/services/use-mission-crews-by-mission.tsx create mode 100644 frontend/src/v2/features/common/types/crew-type.ts create mode 100644 frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx create mode 100644 frontend/src/v2/features/ulam/components/element/mission-crew/mission-crew-form.tsx create mode 100644 frontend/src/v2/features/ulam/components/element/mission-crew/mission-crew-member-list.tsx create mode 100644 frontend/src/v2/features/ulam/components/element/mission-general-information-final-form.tsx create mode 100644 frontend/src/v2/features/ulam/services/use-agent-roles.tsx 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 aecd31e4..dd578759 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 @@ -47,13 +47,13 @@ const MissionPageHeaderWrapper: React.FC = ({ - {formatMissionName(mission?.envData.startDateTimeUtc)} + {formatMissionName(mission?.envData?.startDateTimeUtc)} - + => { + + const queryClient = useQueryClient() + + const addMultipleCrews = (crews: MissionCrew[]): Promise => + axios.post(`crews/multiple`, crews).then(response => response.data) + + const mutation = useMutation({ + mutationFn: addMultipleCrews, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['missionCrew', missionId] }) + } + }) + return mutation +} + +export default useAddMultipleCrewsMutation diff --git a/frontend/src/v2/features/common/services/use-agents.tsx b/frontend/src/v2/features/common/services/use-agents.tsx new file mode 100644 index 00000000..82dac1d2 --- /dev/null +++ b/frontend/src/v2/features/common/services/use-agents.tsx @@ -0,0 +1,17 @@ +import { useQuery } from '@tanstack/react-query' + +import axios from '../../../../query-client/axios.ts' +import { Agent } from '../types/crew-type.ts' + +const useAgentsQuery = () => { + const fetchAgents = (): Promise => axios.get(`agents`).then(response => response.data) + + const query = useQuery({ + queryKey: ['agents'], + queryFn: fetchAgents, + retry: 2 // Retry failed requests twice before throwing an error + }) + return query +} + +export default useAgentsQuery diff --git a/frontend/src/v2/features/common/services/use-delete-crew.tsx b/frontend/src/v2/features/common/services/use-delete-crew.tsx new file mode 100644 index 00000000..014c1dc2 --- /dev/null +++ b/frontend/src/v2/features/common/services/use-delete-crew.tsx @@ -0,0 +1,21 @@ +import { useMutation, UseMutationResult, useQueryClient } from '@tanstack/react-query' + +import axios from '../../../../query-client/axios' + +const useDeleteMissionCrewMutation = (missionId?: string): UseMutationResult => { + + const queryClient = useQueryClient() + + const deleteCrew = (id: number): Promise => + axios.delete(`crews/${id}`).then(response => response.data) + + const mutation = useMutation({ + mutationFn: deleteCrew, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['missionCrew', missionId] }) + } + }) + return mutation +} + +export default useDeleteMissionCrewMutation diff --git a/frontend/src/v2/features/common/services/use-mission-crews-by-mission.tsx b/frontend/src/v2/features/common/services/use-mission-crews-by-mission.tsx new file mode 100644 index 00000000..53c36309 --- /dev/null +++ b/frontend/src/v2/features/common/services/use-mission-crews-by-mission.tsx @@ -0,0 +1,17 @@ +import { useQuery } from '@tanstack/react-query' + +import axios from '../../../../query-client/axios.ts' +import { MissionCrew } from '../types/crew-type.ts' + +const useMissionCrewQuery = (missionId?: string) => { + const fetchMissionCrew = (): Promise => axios.get(`crews/mission/${missionId}`).then(response => response.data) + + const query = useQuery({ + queryKey: ['missionCrew', missionId], + queryFn: fetchMissionCrew, + retry: 2 // Retry failed requests twice before throwing an error + }) + return query +} + +export default useMissionCrewQuery diff --git a/frontend/src/v2/features/common/types/crew-type.ts b/frontend/src/v2/features/common/types/crew-type.ts new file mode 100644 index 00000000..fe73d92d --- /dev/null +++ b/frontend/src/v2/features/common/types/crew-type.ts @@ -0,0 +1,21 @@ +import { Service } from '@common/types/crew-types.ts' + +export type Agent = { + id: number + firstName: string + lastName: string + services: Service[] +} + +export type AgentRole = { + id: string + title: string +} + +export type MissionCrew = { + id?: string + agent?: Agent + comment?: string + role?: AgentRole + missionId?: number +} diff --git a/frontend/src/v2/features/common/types/mission-types.ts b/frontend/src/v2/features/common/types/mission-types.ts index 46fe938a..ff8afec3 100644 --- a/frontend/src/v2/features/common/types/mission-types.ts +++ b/frontend/src/v2/features/common/types/mission-types.ts @@ -1,7 +1,6 @@ -import { ControlUnit } from '@common/types/control-unit-types.ts' +import { ControlResource, ControlUnit } from '@common/types/control-unit-types.ts' import { MissionCrew } from '@common/types/crew-types' import { MissionTypeEnum, SeaFrontEnum } from '@common/types/env-mission-types' -import { MissionStatusEnum } from '@common/types/mission-types' import { Service } from '@common/types/service-types' import { MissionAction } from './mission-action' @@ -29,6 +28,14 @@ export type MissionULAMGeneralInfoInitial = { nbHourAtSea?: number } +export type MissionGeneralInfoFinal = { + resources?: ControlResource[], + crew?: MissionCrew, + isMissionArmed?: boolean, + isJointMission?: boolean, + observations?: string +} + export enum MissionReportTypeEnum { FIELD_REPORT = 'FIELD_REPORT', OFFICE_REPORT = 'OFFICE_REPORT', @@ -57,7 +64,7 @@ export enum CompletenessForStatsStatusEnum { INCOMPLETE = 'INCOMPLETE' } -export enum MissionStatus { +export enum MissionStatusEnum { UPCOMING = 'UPCOMING', IN_PROGRESS = 'IN_PROGRESS', ENDED = 'ENDED', diff --git a/frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx b/frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx new file mode 100644 index 00000000..e9907092 --- /dev/null +++ b/frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx @@ -0,0 +1,146 @@ +import { Accent, Button, ButtonProps, Checkbox, Icon, Label, LabelProps, Size } from '@mtes-mct/monitor-ui' +import React, { useEffect, useState } from 'react' +import { useParams } from 'react-router-dom' +import { Stack, StackProps } from 'rsuite' +import styled from 'styled-components' +import { MissionCrew as MissionCrewModel } from '../../../common/types/crew-type.ts' +import MissionCrewMemberList from './mission-crew/mission-crew-member-list.tsx' +import MissionCrewForm from './mission-crew/mission-crew-form.tsx' +import useMissionCrewQuery from '../../../common/services/use-mission-crews-by-mission.tsx' +import useAddMultipleCrewsMutation from '../../../common/services/use-add-multiple-crews.tsx' +import useAgentsQuery from '../../../common/services/use-agents.tsx' +import useDeleteMissionCrewMutation from '../../../common/services/use-delete-crew.tsx' + + +const TitleLabel = styled((props: LabelProps) => diff --git a/frontend/src/v2/features/ulam/components/element/mission-crew/mission-crew-form.tsx b/frontend/src/v2/features/ulam/components/element/mission-crew/mission-crew-form.tsx index 3e2926d0..ec8b2e07 100644 --- a/frontend/src/v2/features/ulam/components/element/mission-crew/mission-crew-form.tsx +++ b/frontend/src/v2/features/ulam/components/element/mission-crew/mission-crew-form.tsx @@ -9,7 +9,7 @@ import { Size, THEME } from '@mtes-mct/monitor-ui' -import { Form, Formik } from 'formik' +import { Field, FieldProps, Form, Formik } from 'formik' import React, { useEffect, useState } from 'react' import { FlexboxGrid, Stack, StackProps } from 'rsuite' import styled from 'styled-components' @@ -110,21 +110,27 @@ const MissionCrewForm: React.FC = ({ crewList, handleClos - ({ - value: agent.id, - label: `${agent.firstName} ${agent.lastName}` - })) || [] - } - isLight={true} - /> + + {({ field, form }: FieldProps) => ( + ({ + value: agent.id, + label: `${agent.firstName} ${agent.lastName}` + })) || [] + } + isLight={true} + value={field.value} // Assurer que la valeur de Formik est bien passée + onChange={(value: any) => form.setFieldValue(field.name, value)} // Gestion de la sélection + /> + )} + diff --git a/frontend/src/v2/features/ulam/components/element/mission-crew/mission-crew-member-list.tsx b/frontend/src/v2/features/ulam/components/element/mission-crew/mission-crew-member-list.tsx index 0fd1a08d..bbf0325f 100644 --- a/frontend/src/v2/features/ulam/components/element/mission-crew/mission-crew-member-list.tsx +++ b/frontend/src/v2/features/ulam/components/element/mission-crew/mission-crew-member-list.tsx @@ -1,4 +1,4 @@ -import { Accent, Icon, IconButton, IconButtonProps, IconProps, Size } from '@mtes-mct/monitor-ui' +import { Accent, Icon, IconButton, IconButtonProps, Size } from '@mtes-mct/monitor-ui' import { FlexboxGrid, List, ListItemProps, Stack } from 'rsuite' import styled from 'styled-components' import Text, { TextProps } from '@common/components/ui/text.tsx' diff --git a/frontend/src/v2/features/ulam/components/element/mission-general-information-extended-form.tsx b/frontend/src/v2/features/ulam/components/element/mission-general-information-extended-form.tsx new file mode 100644 index 00000000..b6fe870f --- /dev/null +++ b/frontend/src/v2/features/ulam/components/element/mission-general-information-extended-form.tsx @@ -0,0 +1,103 @@ +import { FC, useState } from 'react' +import { Field, FieldProps, Formik } from 'formik' +import { + InterMinisterialService, + MissionGeneralInfoExtended, + MissionReportTypeEnum +} from '../../../common/types/mission-types.ts' +import { + Accent, + Button, + FormikCheckbox, + FormikEffect, + FormikSelect, + FormikTextarea, + Icon, + Size +} from '@mtes-mct/monitor-ui' +import { FlexboxGrid, Stack } from 'rsuite' +import MissionCrewUlam from './mission-crew-ulam.tsx' +import { + useMissionGeneralInformationsExtendedForm +} from '../../../common/hooks/use-mission-general-informations-extended-form.tsx' +import ControlUnitResource from './controlUnitResource/control-unit-resource.tsx' + +export interface MissionGeneralInformationExtendedFormProps { + name: string, + fieldFormik: FieldProps +} + +const MissionGeneralInformationExtendedForm: FC = ({name, fieldFormik}) => { + const { initValue, handleSubmit } = useMissionGeneralInformationsExtendedForm(name, fieldFormik) + const [interMinisterialServices, setInterMinisterialServices] = useState([]) + + const addInterMinisterialService = () => { + const service: InterMinisterialService = { name: "" } + setInterMinisterialServices(prevServices => [...prevServices, service]) + } + + const onClickRemoveMinisterialService = (index: number) => { + setInterMinisterialServices(prevServices => + prevServices.filter((_, i) => i !== index) + ) + } + + return ( + <> + {initValue && ( + + {(formik) => ( + + handleSubmit(newValues)} /> + + + + + + + + + + + + + + {formik.values.isWithInterMinisterialService && ( + + + + )} + + + + + + + + + )} + + )} + + + ) +} + +export default MissionGeneralInformationExtendedForm diff --git a/frontend/src/v2/features/ulam/components/element/mission-general-information-final-form.tsx b/frontend/src/v2/features/ulam/components/element/mission-general-information-final-form.tsx deleted file mode 100644 index 8763444a..00000000 --- a/frontend/src/v2/features/ulam/components/element/mission-general-information-final-form.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { FC } from 'react' -import { FieldProps } from 'formik' -import { MissionGeneralInfoFinal } from '../../../common/types/mission-types.ts' -import { FormikCheckbox, FormikTextarea } from '@mtes-mct/monitor-ui' -import { Stack } from 'rsuite' -import MissionCrewUlam from './mission-crew-ulam.tsx' - -export interface MissionGeneralInformationFinalFormProps { - name: string, - fieldFormik: FieldProps -} - -const MissionGeneralInformationFinalForm: FC = ({name, fieldFormik}) => { - return ( - <> - - - - - - - - - - - - - - - - - - ) -} - -export default MissionGeneralInformationFinalForm 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 index 82602f15..4599aa43 100644 --- 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 @@ -1,13 +1,13 @@ import { Accent, Button, - FormikDateRangePicker, + FormikDateRangePicker, FormikEffect, FormikMultiCheckbox, FormikNumberInput, - FormikSelect, + FormikSelect, Icon, Size } from '@mtes-mct/monitor-ui' import { FieldProps, Formik } from 'formik' -import { FC } from 'react' +import { FC, useEffect } from 'react' import { FlexboxGrid, Stack } from 'rsuite' import { useMissionGeneralInformationsForm } from '../../../common/hooks/use-mission-general-informations-form.tsx' import { useMissionType } from '../../../common/hooks/use-mission-type.tsx' @@ -26,11 +26,11 @@ export interface MissionGeneralInformationInitialFormProps { } const MissionGeneralInformationInitialForm: FC = ({ - name, - fieldFormik, - isCreation = false, - onClose -}) => { + name, + fieldFormik, + isCreation = false, + onClose + }) => { const { initValue, handleSubmit } = useMissionGeneralInformationsForm(name, fieldFormik) const { missionTypeOptions, reportTypeOptions, reinforcementTypeOptions } = useMissionType() @@ -45,13 +45,13 @@ const MissionGeneralInformationInitialForm: FC {initValue && ( - {formik => ( + {(formik) => ( + handleSubmit(newValues)} /> - {formik.values['missionReportType'] === MissionReportTypeEnum.EXTERNAL_REINFORCEMENT_TIME_REPORT && ( + {formik.values.missionReportType === MissionReportTypeEnum.EXTERNAL_REINFORCEMENT_TIME_REPORT && ( {!isCreation && ( - - - + + + )} @@ -135,3 +135,5 @@ const MissionGeneralInformationInitialForm: FC = () => { +const MissionGeneralInformationUlam: React.FC = ({initial, extended, mission}) => { + let { missionId } = useParams() const { handleExecuteOnDelay } = useDelay() - const [value, setValue] = useState() - const handleChange = (nextValue?: NewMissionUlamGeneralInfoInitial) => { - setValue(nextValue) - handleExecuteOnDelay(() => console.log(nextValue)) - } + const debounceTime = useStore(store, state => state.delayQuery.debounceTime) + const mutation = useCreateMissionMutation(missionId); - const initialValues: NewMissionUlamGeneralInfoInitial = { - missionGeneralInfo : { - startDateTimeUtc: "", - endDateTimeUtc: "", - missionTypes: [MissionType.AIR], - reinforcementType: MissionReinforcementTypeEnum.DIRM, - missionReportType: MissionReportTypeEnum.FIELD_REPORT, - nbHourAtSea: 4 - } + const initialValues: NewMissionGeneralInfo = { + initial, + extended } - const finalValues: NewMissionUlamGeneralInfoFinal = { - missionGeneralInfo: { - crew: null, - isJointMission: false, - isMissionArmed: false, - resources: null, - observations: null, + const handleSubmit = (values: NewMissionGeneralInfo) => { + const generalInfos: MissionGeneralInfo2 = { + id: mission?.generalInfos.id, + nbHourAtSea: values.initial.nbHourAtSea, + reinforcementType: values.initial.reinforcementType, + missionReportType: values.initial.missionReportType, + isMissionArmed: values.extended.isMissionArmed, + isAllAgentsParticipating: values.extended.isAllAgentsParticipating, + isWithInterMinisterialService: values.extended.isWithInterMinisterialService, + missionTypes: values.initial.missionTypes, + missionId: Number(missionId), + serviceId: mission?.generalInfos.serviceId, + startDateTimeUtc: values.initial.startDateTimeUtc, + endDateTimeUtc: values.initial.endDateTimeUtc } - } - const handleSubmit = (values: NewMissionUlamGeneralInfoInitial) => { - console.log('submit') - } + handleExecuteOnDelay(async () => { + await mutation.mutateAsync(generalInfos) + if (debounceTime !== undefined) resetDebounceTime() + }, debounceTime) - const handleSubmitFinal = (values: NewMissionUlamGeneralInfoFinal) => { - console.log('submitFinal') - } - const onClose = () => { - console.log('onClose') } return ( - + <> - handleSubmit(newValues as NewMissionUlamGeneralInfoInitial) } /> - + handleSubmit(newValues as NewMissionGeneralInfo)} /> + {(field: FieldProps) => ( )} - - - - - - console.log('submit final')}> - <> - handleSubmitFinal(newValues as NewMissionUlamGeneralInfoFinal) } /> - - {(field: FieldProps) => ( - + {(field: FieldProps) => ( + )} diff --git a/frontend/src/v2/features/ulam/services/use-agent-roles.tsx b/frontend/src/v2/features/ulam/services/use-agent-roles.tsx deleted file mode 100644 index 38b58108..00000000 --- a/frontend/src/v2/features/ulam/services/use-agent-roles.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useQuery } from '@tanstack/react-query' - -import axios from '../../../../query-client/axios.ts' -import { AgentRole } from '../../common/types/crew-type.ts' - -const useAgentRolesQuery = () => { - const fetchAgentRoles = (): Promise => axios.get(`agent_roles`).then(response => response.data) - - const query = useQuery({ - queryKey: ['agentRoles'], - queryFn: fetchAgentRoles, - retry: 2 // Retry failed requests twice before throwing an error - }) - - return query - -} - -export default useAgentRolesQuery() diff --git a/frontend/src/v2/features/ulam/services/use-control-unit-resources.tsx b/frontend/src/v2/features/ulam/services/use-control-unit-resources.tsx new file mode 100644 index 00000000..9c35f418 --- /dev/null +++ b/frontend/src/v2/features/ulam/services/use-control-unit-resources.tsx @@ -0,0 +1,19 @@ +import { useQuery } from '@tanstack/react-query' + +import axios from '../../../../query-client/axios.ts' +import { ControlUnitResource } from '../../common/types/control-unit-types.ts' + +const useControlUnitResourcesQuery = () => { + const fetchControlUnitResources = (): Promise => axios.get(`resources`).then(response => response.data) + + const query = useQuery({ + queryKey: ['controlUnitResources'], + queryFn: fetchControlUnitResources, + retry: 2 // Retry failed requests twice before throwing an error + }) + + return query + +} + +export default useControlUnitResourcesQuery diff --git a/frontend/src/v2/features/ulam/services/use-create-mission.tsx b/frontend/src/v2/features/ulam/services/use-create-mission.tsx index a3c6ecd5..cb6a53a1 100644 --- a/frontend/src/v2/features/ulam/services/use-create-mission.tsx +++ b/frontend/src/v2/features/ulam/services/use-create-mission.tsx @@ -1,14 +1,14 @@ import { useMutation, UseMutationResult, useQueryClient } from '@tanstack/react-query' import axios from '../../../../query-client/axios' -import { Mission, MissionULAMGeneralInfoInitial } from '../../common/types/mission-types.ts' +import { Mission, MissionGeneralInfo2 } from '../../common/types/mission-types.ts' import * as Sentry from '@sentry/react' -const useCreateMissionMutation = (): UseMutationResult => { +const useCreateMissionMutation = (): UseMutationResult => { const queryClient = useQueryClient() - const createMission = (mission: MissionULAMGeneralInfoInitial): Promise => + const createMission = (mission: MissionGeneralInfo2): Promise => axios.post(`/missions`, mission).then(response => response.data) return useMutation({ diff --git a/frontend/src/v2/features/ulam/services/use-update-mission.tsx b/frontend/src/v2/features/ulam/services/use-update-mission.tsx new file mode 100644 index 00000000..89260988 --- /dev/null +++ b/frontend/src/v2/features/ulam/services/use-update-mission.tsx @@ -0,0 +1,27 @@ +import { useMutation, UseMutationResult, useQueryClient } from '@tanstack/react-query' + +import axios from '../../../../query-client/axios' +import { Mission, MissionULAMGeneralInfoInitial } from '../../common/types/mission-types.ts' +import * as Sentry from '@sentry/react' +import { MissionGeneralInfo } from '@common/types/mission-types.ts' + +const useUpdateMissionMutation = (missionId: string): UseMutationResult => { + const queryClient = useQueryClient() + + + const createMission = (mission: MissionULAMGeneralInfoInitial): Promise => + axios.post(`/missions`, mission).then(response => response.data) + + return useMutation({ + mutationFn: createMission, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['mission'] }) + }, + onError: (error) => { + console.error(error) + Sentry.captureException(error) + } + }) +} + +export default useCreateMissionMutation diff --git a/frontend/src/v2/pages/mission-ulam-page.tsx b/frontend/src/v2/pages/mission-ulam-page.tsx index c045abf9..83f4ff80 100644 --- a/frontend/src/v2/pages/mission-ulam-page.tsx +++ b/frontend/src/v2/pages/mission-ulam-page.tsx @@ -18,6 +18,7 @@ import MissionActionUlam from '../features/ulam/components/element/mission-actio import MissionGeneralInformationUlam from '../features/ulam/components/element/mission-general-information-ulam.tsx' import MissionTimelineHeaderUlam from '../features/ulam/components/element/mission-timeline-header-ulam.tsx' import MissionTimelineUlam from '../features/ulam/components/element/mission-timeline-ulam.tsx' +import { MissionGeneralInfoExtended, MissionULAMGeneralInfoInitial } from '../features/common/types/mission-types.ts' const MissionUlamPage: React.FC = () => { const lastSync = useApolloLastSync() @@ -30,6 +31,22 @@ const MissionUlamPage: React.FC = () => { const lastSyncText = lastSync ? formatTime(new Date(parseInt(lastSync!!, 10))) : undefined + const missionGeneralInitial: MissionULAMGeneralInfoInitial = { + startDateTimeUtc: mission?.envData?.startDateTimeUtc, + endDateTimeUtc: mission?.envData?.endDateTimeUtc, + missionTypes: mission?.envData?.missionTypes, + missionReportType: mission?.generalInfos?.missionReportType, + reinforcementType: mission?.generalInfos?.reinforcementType + } + + const missionGeneralExtended: MissionGeneralInfoExtended = { + isMissionArmed: mission?.generalInfos?.isMissionArmed, + isWithInterMinisterialService: mission?.generalInfos?.isWithInterMinisterialService, + observations: mission?.generalInfos?.observations, + resources: mission?.generalInfos?.resources, + crew: mission?.generalInfos?.crew, + } + if (error) return if (isLoading) return @@ -46,7 +63,7 @@ const MissionUlamPage: React.FC = () => { missionGeneralInformations={ } - sectionBody={} + sectionBody={} /> } missionTimeLine={ From 1f260cb95cfe6a36c452f2dfea6b25ab7334df06 Mon Sep 17 00:00:00 2001 From: aleckvincent Date: Thu, 6 Feb 2025 09:34:42 +0100 Subject: [PATCH 07/35] impprove creteUpdate mission --- .../ControlUnitResourceType.kt | 29 ++++++++++ .../generalInfo/MissionGeneralInfoEntity.kt | 3 ++ .../IEnvControlUnitResourceRepository.kt | 8 +++ ...Mission.kt => CreateOrUpdateEnvMission.kt} | 38 ++++++++++--- .../mission/v2/CreateOrUpdateGeneralInfo.kt | 20 +++++++ .../GetControlUnitResources.kt | 15 ++++++ .../api/bff/model/v2/env/ControlUnit.kt | 11 ++++ .../model/v2/env/ControlUnitResourceEnv.kt | 16 ++++++ .../api/bff/model/v2/env/StationData.kt | 8 +++ .../v2/generalInfo/MissionGeneralInfo2.kt | 27 +++++++++- .../v2/ControlUnitResourceRestController.kt | 17 ++++++ .../api/bff/v2/CrewRestController.kt | 7 ++- .../api/bff/v2/MissionRestController.kt | 29 ++++++++-- .../generalInfo/MissionGeneralInfoModel.kt | 21 ++++++-- .../v2/APIEnvControlUnitRepository.kt | 3 -- .../v2/APIEnvControlUnitResourceRepository.kt | 53 +++++++++++++++++++ .../v2/APIEnvMissionRepositoryV2.kt | 1 + .../controllers/MissionRestControllerTest.kt | 6 +-- 18 files changed, 288 insertions(+), 24 deletions(-) create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/env/controlResources/ControlUnitResourceType.kt create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/repositories/v2/controlUnitResource/IEnvControlUnitResourceRepository.kt rename backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/{CreateEnvMission.kt => CreateOrUpdateEnvMission.kt} (55%) create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/v2/CreateOrUpdateGeneralInfo.kt create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/v2/controlUnitResource/GetControlUnitResources.kt create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/ControlUnit.kt create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/ControlUnitResourceEnv.kt create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/StationData.kt create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/ControlUnitResourceRestController.kt create mode 100644 backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvControlUnitResourceRepository.kt diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/env/controlResources/ControlUnitResourceType.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/env/controlResources/ControlUnitResourceType.kt new file mode 100644 index 00000000..8eb99846 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/env/controlResources/ControlUnitResourceType.kt @@ -0,0 +1,29 @@ +package fr.gouv.dgampa.rapportnav.domain.entities.mission.env.controlResources + +enum class ControlUnitResourceType(val label: String) { + AIRPLANE("Avion"), + BARGE("Barge"), + CAR("Voiture"), + DRONE("Drône"), + EQUESTRIAN("Équestre"), + FAST_BOAT("Vedette"), + FRIGATE("Frégate"), + HELICOPTER("Hélicoptère"), + HYDROGRAPHIC_SHIP("Bâtiment hydrographique"), + KAYAK("Kayak"), + LIGHT_FAST_BOAT("Vedette légère"), + MINE_DIVER("Plongeur démineur"), + MOTORCYCLE("Moto"), + NET_LIFTER("Remonte-filets"), + NO_RESOURCE("Aucun moyen"), + OTHER("Autre"), + PATROL_BOAT("Patrouilleur"), + PEDESTRIAN("Piéton"), + PIROGUE("Pirogue"), + RIGID_HULL("Coque rigide"), + SEA_SCOOTER("Scooter de mer"), + SEMI_RIGID("Semi-rigide"), + SUPPORT_SHIP("Bâtiment de soutien"), + TRAINING_SHIP("Bâtiment-école"), + TUGBOAT("Remorqueur"), +} diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/nav/generalInfo/MissionGeneralInfoEntity.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/nav/generalInfo/MissionGeneralInfoEntity.kt index 9d675e20..0fbc2e8d 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/nav/generalInfo/MissionGeneralInfoEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/entities/mission/nav/generalInfo/MissionGeneralInfoEntity.kt @@ -11,4 +11,7 @@ data class MissionGeneralInfoEntity( var serviceId: Int? = null, @MandatoryForStats var nbrOfRecognizedVessel: Int? = null, + var isWithInterMinisterialService: Boolean? = false, + var isAllAgentsParticipating: Boolean? = false, + var isMissionArmed: Boolean? = false ) diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/repositories/v2/controlUnitResource/IEnvControlUnitResourceRepository.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/repositories/v2/controlUnitResource/IEnvControlUnitResourceRepository.kt new file mode 100644 index 00000000..a3c82ecb --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/repositories/v2/controlUnitResource/IEnvControlUnitResourceRepository.kt @@ -0,0 +1,8 @@ +package fr.gouv.dgampa.rapportnav.domain.repositories.v2.controlUnitResource + +import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.env.ControlUnitResourceEnv + +interface IEnvControlUnitResourceRepository { + + fun findAll(): List? +} diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/CreateEnvMission.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/CreateOrUpdateEnvMission.kt similarity index 55% rename from backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/CreateEnvMission.kt rename to backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/CreateOrUpdateEnvMission.kt index bbfc75f9..984f7267 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/CreateEnvMission.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/CreateOrUpdateEnvMission.kt @@ -6,16 +6,18 @@ import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.controlResources.Le import fr.gouv.dgampa.rapportnav.domain.entities.mission.v2.env.MissionEnvEntity import fr.gouv.dgampa.rapportnav.domain.repositories.v2.controlUnit.IEnvControlUnitRepository import fr.gouv.dgampa.rapportnav.domain.repositories.v2.mission.IEnvMissionRepository +import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.v2.CreateOrUpdateGeneralInfo import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.MissionEnv import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.generalInfo.MissionGeneralInfo2 import org.slf4j.LoggerFactory @UseCase -class CreateEnvMission( +class CreateOrUpdateEnvMission( private val monitorEnvRepo: IEnvMissionRepository, - private val monitorEnvControlUnitRepo: IEnvControlUnitRepository + private val monitorEnvControlUnitRepo: IEnvControlUnitRepository, + private val createOrUpdateGeneralInfo: CreateOrUpdateGeneralInfo ) { - private val logger = LoggerFactory.getLogger(CreateEnvMission::class.java) + private val logger = LoggerFactory.getLogger(CreateOrUpdateEnvMission::class.java) fun execute(missionGeneralInfo: MissionGeneralInfo2, controlUnitIds: List?): MissionEnvEntity? { try { @@ -30,12 +32,13 @@ class CreateEnvMission( } if (matchedControlUnits.isEmpty()) { - throw Exception("CreateEnvMission : controlUnits is empty for this user") + throw Exception("CreateOrUpdateEnvMission : controlUnits is empty for this user") } val missionEnv = MissionEnv( + id = missionGeneralInfo.missionId, missionTypes = missionGeneralInfo.missionTypes, - missionSource = MissionSourceEnum.MONITORENV, + missionSource = MissionSourceEnum.RAPPORTNAV, startDateTimeUtc = missionGeneralInfo.startDateTimeUtc, endDateTimeUtc = missionGeneralInfo.endDateTimeUtc, controlUnits = matchedControlUnits, @@ -44,10 +47,31 @@ class CreateEnvMission( isGeometryComputedFromControls = false, //TODO: a checker ) - return monitorEnvRepo.createMission(missionEnv) + val result = monitorEnvRepo.createMission(missionEnv) + + if (result !== null) { + createOrUpdateGeneralInfo.execute( + MissionGeneralInfo2( + id = missionGeneralInfo.id, + missionId = result.id!!, + startDateTimeUtc = missionGeneralInfo.startDateTimeUtc, + endDateTimeUtc = missionGeneralInfo.endDateTimeUtc, + missionTypes = missionGeneralInfo.missionTypes, + isAllAgentsParticipating = missionGeneralInfo.isAllAgentsParticipating, + isWithInterMinisterialService = missionGeneralInfo.isWithInterMinisterialService, + missionReportType = missionGeneralInfo.missionReportType, + reinforcementType = missionGeneralInfo.reinforcementType + ) + ) + + logger.info("GeneralInfo save or update successfully") + + } + + return result } catch (e: Exception) { - logger.error("CreateEnvMission failed creating missions", e) + logger.error("CreateOrUpdateEnvMission failed creating missions", e) return null } } diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/v2/CreateOrUpdateGeneralInfo.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/v2/CreateOrUpdateGeneralInfo.kt new file mode 100644 index 00000000..5fb67b70 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/v2/CreateOrUpdateGeneralInfo.kt @@ -0,0 +1,20 @@ +package fr.gouv.dgampa.rapportnav.domain.use_cases.mission.v2 + +import fr.gouv.dgampa.rapportnav.config.UseCase +import fr.gouv.dgampa.rapportnav.domain.entities.mission.v2.MissionGeneralInfoEntity2 +import fr.gouv.dgampa.rapportnav.domain.repositories.mission.generalInfo.IMissionGeneralInfoRepository +import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.generalInfo.MissionGeneralInfo2 + +@UseCase +class CreateOrUpdateGeneralInfo(private val repository: IMissionGeneralInfoRepository) { + + fun execute(generalInfo2: MissionGeneralInfo2): MissionGeneralInfoEntity2 { + + val generalInfoModel = repository.save(generalInfo2.toMissionGeneralInfoEntity()) + + return MissionGeneralInfoEntity2( + data = generalInfoModel.toMissionGeneralInfoEntity() + ) + + } +} diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/v2/controlUnitResource/GetControlUnitResources.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/v2/controlUnitResource/GetControlUnitResources.kt new file mode 100644 index 00000000..be9c01f6 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/v2/controlUnitResource/GetControlUnitResources.kt @@ -0,0 +1,15 @@ +package fr.gouv.dgampa.rapportnav.domain.use_cases.mission.v2.controlUnitResource + +import fr.gouv.dgampa.rapportnav.config.UseCase +import fr.gouv.dgampa.rapportnav.domain.repositories.v2.controlUnitResource.IEnvControlUnitResourceRepository +import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.env.ControlUnitResourceEnv + +@UseCase +class GetControlUnitResources( + private val repository: IEnvControlUnitResourceRepository +) { + + fun execute(): List? { + return repository.findAll() + } +} diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/ControlUnit.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/ControlUnit.kt new file mode 100644 index 00000000..8c7fd027 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/ControlUnit.kt @@ -0,0 +1,11 @@ +package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.env + +data class ControlUnit( + val id: Int, + val areaNote: String? = null, + val administrationId: Int, + val departmentAreaInseeCode: String? = null, + val isArchived: Boolean, + val name: String, + val termsNote: String? = null, +) diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/ControlUnitResourceEnv.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/ControlUnitResourceEnv.kt new file mode 100644 index 00000000..cbd7daff --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/ControlUnitResourceEnv.kt @@ -0,0 +1,16 @@ +package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.env + +import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.controlResources.ControlUnitResourceType + +data class ControlUnitResourceEnv( + val id: Int, + val controlUnit: ControlUnit, + val controlUnitId: Int, + val isArchived: Boolean, + val name: String, + val note: String? = null, + val photo: ByteArray? = byteArrayOf(), + val station: StationData, + val stationId: Int, + val type: ControlUnitResourceType, +) diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/StationData.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/StationData.kt new file mode 100644 index 00000000..b5dbd0ee --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/env/StationData.kt @@ -0,0 +1,8 @@ +package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.env + +data class StationData( + val id: Int, + val latitude: Double, + val longitude: Double, + val name: String, +) diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/generalInfo/MissionGeneralInfo2.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/generalInfo/MissionGeneralInfo2.kt index f09574ac..d247c5a7 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/generalInfo/MissionGeneralInfo2.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/model/v2/generalInfo/MissionGeneralInfo2.kt @@ -3,6 +3,7 @@ package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.generalInfo import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.MissionEntity import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.MissionTypeEnum import fr.gouv.dgampa.rapportnav.domain.entities.mission.nav.ServiceEntity +import fr.gouv.dgampa.rapportnav.domain.entities.mission.nav.generalInfo.MissionGeneralInfoEntity import fr.gouv.dgampa.rapportnav.domain.entities.mission.v2.MissionGeneralInfoEntity2 import fr.gouv.dgampa.rapportnav.domain.entities.mission.v2.MissionReinforcementTypeEnum import fr.gouv.dgampa.rapportnav.domain.entities.mission.v2.MissionReportTypeEnum @@ -11,6 +12,7 @@ import java.time.Instant data class MissionGeneralInfo2( val id: Int? = null, + val missionId: Int, val startDateTimeUtc: Instant, val endDateTimeUtc: Instant? = null, val missionReportType: MissionReportTypeEnum, @@ -23,7 +25,10 @@ data class MissionGeneralInfo2( var serviceId: Int? = null, var nbrOfRecognizedVessel: Int? = null, val crew: List? = null, - val services: List? = null + val services: List? = null, + val isWithInterMinisterialService: Boolean? = false, + val isAllAgentsParticipating: Boolean? = false, + val isMissionArmed: Boolean? = false ) { companion object { fun fromMissionGeneralInfoEntity( @@ -31,6 +36,7 @@ data class MissionGeneralInfo2( generalInfo2: MissionGeneralInfoEntity2? ): MissionGeneralInfo2 { return MissionGeneralInfo2( + missionId = generalInfo2?.data?.missionId!!, id = generalInfo2?.data?.id, startDateTimeUtc = envData.startDateTimeUtc, endDateTimeUtc = envData.endDateTimeUtc, @@ -44,7 +50,26 @@ data class MissionGeneralInfo2( nbrOfRecognizedVessel = generalInfo2?.data?.nbrOfRecognizedVessel, services = generalInfo2?.services, crew = generalInfo2?.crew?.map { MissionCrew.fromMissionCrewEntity(it) }, + isAllAgentsParticipating = generalInfo2?.data?.isAllAgentsParticipating, + isWithInterMinisterialService = generalInfo2?.data?.isWithInterMinisterialService, + isMissionArmed = generalInfo2?.data?.isMissionArmed + ) } } + + fun toMissionGeneralInfoEntity(): MissionGeneralInfoEntity { + return MissionGeneralInfoEntity( + id = id!!, + missionId = missionId, + distanceInNauticalMiles = distanceInNauticalMiles, + consumedGOInLiters = consumedGOInLiters, + consumedFuelInLiters = consumedFuelInLiters, + serviceId = serviceId, + nbrOfRecognizedVessel = nbrOfRecognizedVessel, + isWithInterMinisterialService = isWithInterMinisterialService, + isAllAgentsParticipating = isAllAgentsParticipating, + isMissionArmed = isMissionArmed + ) + } } diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/ControlUnitResourceRestController.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/ControlUnitResourceRestController.kt new file mode 100644 index 00000000..a82326b1 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/ControlUnitResourceRestController.kt @@ -0,0 +1,17 @@ +package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.v2 + +import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.v2.controlUnitResource.GetControlUnitResources +import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.env.ControlUnitResourceEnv +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + + +@RestController +@RequestMapping("/api/v2/resources") +class ControlUnitResourceRestController( + private val getControlUnitResources: GetControlUnitResources +) { + fun getAll(): List? { + return getControlUnitResources.execute() + } +} diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/CrewRestController.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/CrewRestController.kt index 2b1b2fcc..a8628026 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/CrewRestController.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/CrewRestController.kt @@ -1,14 +1,13 @@ package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.v2 -import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.crew.AddOrUpdateMissionCrew -import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.crew.DeleteMissionCrew -import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.crew.MissionCrew import fr.gouv.dgampa.rapportnav.domain.use_cases.service.GetCrewByServiceId import fr.gouv.dgampa.rapportnav.domain.use_cases.service.GetServices import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.crew.ServiceWithAgents import io.swagger.v3.oas.annotations.Operation import org.slf4j.LoggerFactory -import org.springframework.web.bind.annotation.* +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api/v2/crews") diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/MissionRestController.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/MissionRestController.kt index 1ff34f92..7e993a67 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/MissionRestController.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/api/bff/v2/MissionRestController.kt @@ -1,5 +1,7 @@ package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.v2 +import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.MissionEntity +import fr.gouv.dgampa.rapportnav.domain.entities.mission.v2.env.MissionEnvEntity import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.* import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.action.v2.GetEnvMissionById2 import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.v2.GetMission2 @@ -18,7 +20,7 @@ import kotlin.collections.plus @RequestMapping("/api/v2/missions") class MissionRestController( private val getMission2: GetMission2, - private val createEnvMission: CreateEnvMission, + private val createOrUpdateEnvMission: CreateOrUpdateEnvMission, private val getEnvMissionById2: GetEnvMissionById2, private val getControlUnitsForUser: GetControlUnitsForUser, private val getUserFromToken: GetUserFromToken, @@ -107,11 +109,11 @@ class MissionRestController( */ @PostMapping("") @Operation(summary = "Create a new MonitorEnv mission") - fun createMission( + fun create( @RequestBody body: MissionGeneralInfo2 ): MissionEnv? { try { - val mission = createEnvMission.execute( + val mission = createOrUpdateEnvMission.execute( missionGeneralInfo = body, controlUnitIds = getControlUnitsForUser.execute() ) ?: return null @@ -121,4 +123,25 @@ class MissionRestController( return null } } + + @PutMapping("/missionId") + fun update( + @RequestBody body: MissionGeneralInfo2, + @PathVariable missionId: Int + ): MissionEnv? { + if ((body.id == null) || (missionId != body.id)) { + logger.error("Error on update mission : missionId doesn't match with request param") + throw java.lang.IllegalArgumentException("missionId doesn't match with request param") + } + try { + val mission = createOrUpdateEnvMission.execute( + missionGeneralInfo = body, + controlUnitIds = getControlUnitsForUser.execute(), + )?: return null + return MissionEnv.fromMissionEnvEntity(mission) + } catch (e: Exception) { + logger.error("Error while updating MonitorEnv mission : ", e) + return null + } + } } diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/model/mission/generalInfo/MissionGeneralInfoModel.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/model/mission/generalInfo/MissionGeneralInfoModel.kt index bafae15d..0eab702c 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/model/mission/generalInfo/MissionGeneralInfoModel.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/database/model/mission/generalInfo/MissionGeneralInfoModel.kt @@ -29,7 +29,16 @@ class MissionGeneralInfoModel( var serviceId: Int? = null, @Column(name = "nbr_of_recognized_vessel", nullable = true) - var nbrOfRecognizedVessel: Int? = null + var nbrOfRecognizedVessel: Int? = null, + + @Column(name = "is_with_interministerial_service", nullable = true) + var isWithInterMinisterialService: Boolean? = false, + + @Column(name = "is_all_agents_participating", nullable = true) + var isAllAgentsParticipating: Boolean? = false, + + @Column(name = "is_mission_armed", nullable = true) + var isMissionArmed: Boolean? = false ) { fun toMissionGeneralInfoEntity(): MissionGeneralInfoEntity { return MissionGeneralInfoEntity( @@ -39,7 +48,10 @@ class MissionGeneralInfoModel( consumedGOInLiters, consumedFuelInLiters, serviceId, - nbrOfRecognizedVessel + nbrOfRecognizedVessel, + isWithInterMinisterialService, + isAllAgentsParticipating, + isMissionArmed ) } @@ -51,7 +63,10 @@ class MissionGeneralInfoModel( consumedGOInLiters = info.consumedGOInLiters, consumedFuelInLiters = info.consumedFuelInLiters, serviceId = info.serviceId, - nbrOfRecognizedVessel = info.nbrOfRecognizedVessel + nbrOfRecognizedVessel = info.nbrOfRecognizedVessel, + isWithInterMinisterialService = info.isWithInterMinisterialService, + isAllAgentsParticipating = info.isAllAgentsParticipating, + isMissionArmed = info.isMissionArmed ) } } diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvControlUnitRepository.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvControlUnitRepository.kt index 994c7078..0afcbdf4 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvControlUnitRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvControlUnitRepository.kt @@ -6,7 +6,6 @@ import fr.gouv.dgampa.rapportnav.config.HttpClientFactory import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.controlResources.LegacyControlUnitEntity import fr.gouv.dgampa.rapportnav.domain.repositories.v2.controlUnit.IEnvControlUnitRepository import fr.gouv.dgampa.rapportnav.infrastructure.monitorenv.v2.outputs.LegacyControlUnitDataOutput -import fr.gouv.dgampa.rapportnav.infrastructure.utils.GsonSerializer import org.n52.jackson.datatype.jts.JtsModule import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -23,8 +22,6 @@ class APIEnvControlUnitRepository( private val logger: Logger = LoggerFactory.getLogger(APIEnvControlUnitRepository::class.java); - private val gson = GsonSerializer().create() - private val client = clientFactory.create(); // private val host = System.getenv("MONITORENV_HOST") diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvControlUnitResourceRepository.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvControlUnitResourceRepository.kt new file mode 100644 index 00000000..1bd5e4d7 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvControlUnitResourceRepository.kt @@ -0,0 +1,53 @@ +package fr.gouv.dgampa.rapportnav.infrastructure.monitorenv.v2 + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import fr.gouv.dgampa.rapportnav.config.HttpClientFactory +import fr.gouv.dgampa.rapportnav.domain.repositories.v2.controlUnitResource.IEnvControlUnitResourceRepository +import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.env.ControlUnitResourceEnv +import org.n52.jackson.datatype.jts.JtsModule +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Repository +import java.net.URI +import java.net.http.HttpRequest +import java.net.http.HttpResponse + +@Repository +class APIEnvControlUnitResourceRepository( + clientFactory: HttpClientFactory, + private val mapper: ObjectMapper +): IEnvControlUnitResourceRepository { + + private val logger = LoggerFactory.getLogger(APIEnvControlUnitResourceRepository::class.java) + private val client = clientFactory.create(); + + private val host = "https://monitorenv.din.developpement-durable.gouv.fr" // TODO: to be replaced by env var + override fun findAll(): List? { + val url = "$host/api/v1/control_units"; + logger.info("Sending GET request for Env control unit resources fetching URL: $url") + return try { + + val request = HttpRequest + .newBuilder() + .uri(URI.create(url)) + .build(); + + val response = client.send(request, HttpResponse.BodyHandlers.ofString()); + logger.info("APIEnvControlUnitResourceRepository::findAll Response received, Status code: ${response.statusCode()}"); + + val body = response.body() + logger.info("APIEnvControlUnitResourceRepository::findAll Response received, Content: $body") + + if (response.statusCode() == 400 || response.statusCode() == 500) { + throw Exception("Error while fetching control unit resources from env, please check the logs") + } + + mapper.registerModule(JtsModule()) + + mapper.readValue(body); + } catch (e: Exception) { + logger.error("Failed to GET request for Env legacy control units fetching. URL: $url", e); + null; + } + } +} diff --git a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvMissionRepositoryV2.kt b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvMissionRepositoryV2.kt index 3893bc1d..44d9e70a 100644 --- a/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvMissionRepositoryV2.kt +++ b/backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/infrastructure/monitorenv/v2/APIEnvMissionRepositoryV2.kt @@ -3,6 +3,7 @@ package fr.gouv.dgampa.rapportnav.infrastructure.monitorenv.v2 import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import fr.gouv.dgampa.rapportnav.config.HttpClientFactory +import fr.gouv.dgampa.rapportnav.domain.entities.mission.v2.MissionEntity2 import fr.gouv.dgampa.rapportnav.domain.entities.mission.v2.env.MissionEnvEntity import fr.gouv.dgampa.rapportnav.domain.repositories.v2.mission.IEnvMissionRepository import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.MissionEnv diff --git a/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/infrastructure/bff/controllers/MissionRestControllerTest.kt b/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/infrastructure/bff/controllers/MissionRestControllerTest.kt index 5e9ace96..17c50eeb 100644 --- a/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/infrastructure/bff/controllers/MissionRestControllerTest.kt +++ b/backend/src/test/kotlin/fr/gouv/gmampa/rapportnav/infrastructure/bff/controllers/MissionRestControllerTest.kt @@ -52,7 +52,7 @@ class MissionRestControllerTest { private lateinit var fakeMissionData2: FakeMissionData2 @MockitoBean - private lateinit var createEnvMission: CreateEnvMission + private lateinit var createOrUpdateEnvMission: CreateOrUpdateEnvMission @MockitoBean private lateinit var getEnvMissionById2: GetEnvMissionById2 @@ -113,7 +113,7 @@ class MissionRestControllerTest { controlUnits = listOf(LegacyControlUnitEntityMock.create(id = controlUnitsIds.first())) ) `when`(getControlUnitsForUser.execute()).thenReturn(controlUnitsIds) - `when`(createEnvMission.execute(requestBody, controlUnitsIds)).thenReturn(mockMission) + `when`(createOrUpdateEnvMission.execute(requestBody, controlUnitsIds)).thenReturn(mockMission) // Act & Assert mockMvc.perform( @@ -136,7 +136,7 @@ class MissionRestControllerTest { `when`(getControlUnitsForUser.execute()).thenReturn(controlUnitsIds) // Simulate mission creation returning null `when`( - createEnvMission.execute( + createOrUpdateEnvMission.execute( requestBody, controlUnitsIds ) From 5d9e5cb7c55badcc72e16166dbb515f7e6f358c5 Mon Sep 17 00:00:00 2001 From: aleckvincent Date: Thu, 6 Feb 2025 09:56:34 +0100 Subject: [PATCH 08/35] add patchObservationByUnit --- .../elements/mission-observations-unit.tsx | 78 +++++++++++++++++++ ...sion-general-information-extended-form.tsx | 10 --- .../mission-general-information-ulam.tsx | 4 + 3 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 frontend/src/v2/features/common/components/elements/mission-observations-unit.tsx diff --git a/frontend/src/v2/features/common/components/elements/mission-observations-unit.tsx b/frontend/src/v2/features/common/components/elements/mission-observations-unit.tsx new file mode 100644 index 00000000..3ea4681d --- /dev/null +++ b/frontend/src/v2/features/common/components/elements/mission-observations-unit.tsx @@ -0,0 +1,78 @@ +import { FormikEffect, FormikTextarea } from '@mtes-mct/monitor-ui' +import { Formik } from 'formik' +import React, { useEffect, useRef, useState } from 'react' +import useIsMissionFinished from '@features/pam/mission/hooks/use-is-mission-finished.tsx' +import usePatchMissionEnv from '@features/pam/mission/hooks/use-patch-mission-env.tsx' + +const DEBOUNCE_TIME_TRIGGER = 5000 + +type ObservationsByUnit = { + observations?: string +} + +interface MissionObservationsByUnitProps { + missionId: number + observationsByUnit?: string +} + +const MissionObservationsUnit: React.FC = ({ missionId, observationsByUnit }) => { + const [patchMissionObservation] = usePatchMissionEnv() + const isMissionFinished = useIsMissionFinished(missionId?.toString()) + + const timerRef = useRef>() + const [initValue, setInitValue] = useState() + + useEffect(() => { + setInitValue({ observations: observationsByUnit }) + }, [observationsByUnit]) + + const handleSubmit = async ({ observations }: ObservationsByUnit): Promise => { + clearTimeout(timerRef.current) + timerRef.current = setTimeout(() => patchObservationUnit(observations), DEBOUNCE_TIME_TRIGGER) + } + + const patchObservationUnit = async (observations?: string) => { + if (observations === observationsByUnit) return + await patchMissionObservation({ + variables: { + mission: { + missionId, + observationsByUnit: observations ?? '' + } + } + }) + } + + const validateError = (isMissionFinished?: boolean, observations?: string) => + isMissionFinished && !observations + ? { observations: "L'observation générale de la mission est requise" } + : undefined + + return ( + <> + {initValue && ( + validateError(isMissionFinished, values.observations)} + > + <> + + + + + )} + + ) +} + +export default MissionObservationsUnit diff --git a/frontend/src/v2/features/ulam/components/element/mission-general-information-extended-form.tsx b/frontend/src/v2/features/ulam/components/element/mission-general-information-extended-form.tsx index b6fe870f..acb19053 100644 --- a/frontend/src/v2/features/ulam/components/element/mission-general-information-extended-form.tsx +++ b/frontend/src/v2/features/ulam/components/element/mission-general-information-extended-form.tsx @@ -81,16 +81,6 @@ const MissionGeneralInformationExtendedForm: FC )} - - - - - - - )} diff --git a/frontend/src/v2/features/ulam/components/element/mission-general-information-ulam.tsx b/frontend/src/v2/features/ulam/components/element/mission-general-information-ulam.tsx index a0115862..2254f241 100644 --- a/frontend/src/v2/features/ulam/components/element/mission-general-information-ulam.tsx +++ b/frontend/src/v2/features/ulam/components/element/mission-general-information-ulam.tsx @@ -15,6 +15,7 @@ import { useStore } from '@tanstack/react-store' import { store } from '../../../../store' import { resetDebounceTime } from '../../../../store/slices/delay-query-reducer.ts' import useCreateMissionMutation from '../../services/use-create-mission.tsx' +import MissionObservationsUnit from '../../../common/components/elements/mission-observations-unit.tsx' type MissionGeneralInformationUlamProps = { initial?: MissionULAMGeneralInfoInitial, @@ -84,6 +85,9 @@ const MissionGeneralInformationUlam: React.FC + + + ) From 449c1b26437470b8893683cc791787175d7cd2f2 Mon Sep 17 00:00:00 2001 From: aleckvincent Date: Thu, 6 Feb 2025 10:13:20 +0100 Subject: [PATCH 09/35] improve GeneralInfo ui --- .../components/element/mission-crew-ulam.tsx | 6 +-- ...sion-general-information-extended-form.tsx | 2 +- ...ssion-general-information-initial-form.tsx | 4 +- .../mission-general-information-ulam.tsx | 49 ++++++++++++------- frontend/src/v2/pages/mission-ulam-page.tsx | 2 - 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx b/frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx index 95b27221..9d60edd1 100644 --- a/frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx +++ b/frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx @@ -28,7 +28,7 @@ const UnderlineStack = styled((props: StackProps) => ( - - )} - - ) - - -} - -export default ControlUnitResource 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 index cf1fc5ef..20baf5f0 100644 --- a/frontend/src/v2/features/ulam/components/element/mission-create-dialog.tsx +++ b/frontend/src/v2/features/ulam/components/element/mission-create-dialog.tsx @@ -1,35 +1,31 @@ -import React, { FC, useEffect, useState } from 'react' import { Accent, Dialog, Icon, IconButton, Size, THEME } from '@mtes-mct/monitor-ui' -import { FlexboxGrid, Stack } from 'rsuite' -import { MissionTypeEnum } from '@common/types/env-mission-types.ts' -import MissionGeneralInformationUlamFormNew from './mission-general-information-ulam-form-new.tsx' +import { FC, useEffect, useState } from 'react' +import { FlexboxGrid } from 'rsuite' +import MissionCreateNewUlam from './mission-create-new-ulam.tsx' interface MissionCreateDialogProps { isOpen: boolean onClose: () => void } -const MissionCreateDialog: FC = ({isOpen, onClose}) => { - +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 + Création d'un rapport de mission = ({isOpen, onClose}) => - + ) diff --git a/frontend/src/v2/features/ulam/components/element/mission-create-new-ulam.tsx b/frontend/src/v2/features/ulam/components/element/mission-create-new-ulam.tsx new file mode 100644 index 00000000..e34aee3c --- /dev/null +++ b/frontend/src/v2/features/ulam/components/element/mission-create-new-ulam.tsx @@ -0,0 +1,70 @@ +import { Accent, Button } from '@mtes-mct/monitor-ui' +import { formatISO } from 'date-fns' +import { Field, FieldProps, Formik } from 'formik' +import React from 'react' +import { useNavigate } from 'react-router-dom' +import { Stack } from 'rsuite' +import { MissionULAMGeneralInfoInitial } from '../../../common/types/mission-types.ts' +import useCreateMissionMutation from '../../services/use-create-mission.tsx' +import MissionGeneralInformationInitialFormUlam from './mission-general-information-initial-form-ulam.tsx' + +type NewMissionUlam = { missionGeneralInfo: MissionULAMGeneralInfoInitial } + +export interface MissionCreateNewUlamProps { + onClose?: () => void +} + +const MissionCreateNewUlam: React.FC = ({ onClose }) => { + const navigate = useNavigate() + const mutation = useCreateMissionMutation() + + const initialValues: NewMissionUlam = { + missionGeneralInfo: { + startDateTimeUtc: formatISO(new Date()), + endDateTimeUtc: formatISO(new Date()) + } as MissionULAMGeneralInfoInitial + } + + const handleSubmit = ({ missionGeneralInfo }: NewMissionUlam, errors: any) => { + mutation.mutateAsync(missionGeneralInfo).then(r => navigate(`/v2/ulam/missions/${r.id}`)) + if (onClose) onClose() + } + + return ( + <> + + {formik => ( + + + + {(field: FieldProps) => ( + + )} + + + + + + + + + )} + + + ) +} + +export default MissionCreateNewUlam diff --git a/frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx b/frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx deleted file mode 100644 index 9d60edd1..00000000 --- a/frontend/src/v2/features/ulam/components/element/mission-crew-ulam.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { Accent, Button, ButtonProps, Checkbox, Icon, Label, LabelProps, Size } from '@mtes-mct/monitor-ui' -import React, { useEffect, useState } from 'react' -import { useParams } from 'react-router-dom' -import { Stack, StackProps } from 'rsuite' -import styled from 'styled-components' -import { MissionCrew as MissionCrewModel } from '../../../common/types/crew-type.ts' -import MissionCrewMemberList from './mission-crew/mission-crew-member-list.tsx' -import MissionCrewForm from './mission-crew/mission-crew-form.tsx' -import useMissionCrewQuery from '../../../common/services/use-mission-crews-by-mission.tsx' -import useAddMultipleCrewsMutation from '../../../common/services/use-add-multiple-crews.tsx' -import useAgentsQuery from '../../../common/services/use-agents.tsx' -import useDeleteMissionCrewMutation from '../../../common/services/use-delete-crew.tsx' - - -const TitleLabel = styled((props: LabelProps) =>