diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ReportingsController.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ReportingsController.kt index 2b60b26fa..1c60f2b24 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ReportingsController.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ReportingsController.kt @@ -16,7 +16,6 @@ import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.tags.Tag import jakarta.websocket.server.PathParam -import java.time.ZonedDateTime import org.springframework.format.annotation.DateTimeFormat import org.springframework.http.HttpStatus import org.springframework.web.bind.annotation.DeleteMapping @@ -28,67 +27,68 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.ResponseStatus import org.springframework.web.bind.annotation.RestController +import java.time.ZonedDateTime @RestController @RequestMapping("/bff/v1/reportings") @Tag(description = "API des Signalements", name = "Reportings") class ReportingsController( - private val createOrUpdateReporting: CreateOrUpdateReporting, - private val getReportingById: GetReportingById, - private val getReportings: GetReportings, - private val deleteReporting: DeleteReporting, - private val deleteReportings: DeleteReportings, - private val archiveReportings: ArchiveReportings, - private val mapper: ObjectMapper, + private val createOrUpdateReporting: CreateOrUpdateReporting, + private val getReportingById: GetReportingById, + private val getReportings: GetReportings, + private val deleteReporting: DeleteReporting, + private val deleteReportings: DeleteReportings, + private val archiveReportings: ArchiveReportings, + private val mapper: ObjectMapper, ) { @GetMapping("") @Operation(summary = "Get reportings") fun getReportingsController( - @Parameter(description = "page number") - @RequestParam(name = "pageNumber") - pageNumber: Int?, - @Parameter(description = "page size") @RequestParam(name = "pageSize") pageSize: Int?, - @Parameter(description = "Reporting created after date") - @RequestParam(name = "startedAfterDateTime", required = false) - @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) - startedAfterDateTime: ZonedDateTime?, - @Parameter(description = "Reporting created before date") - @RequestParam(name = "startedBeforeDateTime", required = false) - @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) - startedBeforeDateTime: ZonedDateTime?, - @Parameter(description = "Reporting type") - @RequestParam(name = "reportingType", required = false) - reportingType: List?, - @Parameter(description = "Facades") - @RequestParam(name = "seaFronts", required = false) - seaFronts: List?, - @Parameter(description = "Reporting source types") - @RequestParam(name = "sourcesType", required = false) - sourcesType: List?, - @Parameter(description = "Reporting status") - @RequestParam(name = "status", required = false) - status: List?, + @Parameter(description = "page number") + @RequestParam(name = "pageNumber") + pageNumber: Int?, + @Parameter(description = "page size") @RequestParam(name = "pageSize") pageSize: Int?, + @Parameter(description = "Reporting created after date") + @RequestParam(name = "startedAfterDateTime", required = false) + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + startedAfterDateTime: ZonedDateTime?, + @Parameter(description = "Reporting created before date") + @RequestParam(name = "startedBeforeDateTime", required = false) + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + startedBeforeDateTime: ZonedDateTime?, + @Parameter(description = "Reporting type") + @RequestParam(name = "reportingType", required = false) + reportingType: List?, + @Parameter(description = "Facades") + @RequestParam(name = "seaFronts", required = false) + seaFronts: List?, + @Parameter(description = "Reporting source types") + @RequestParam(name = "sourcesType", required = false) + sourcesType: List?, + @Parameter(description = "Reporting status") + @RequestParam(name = "status", required = false) + status: List?, ): List { return getReportings.execute( - pageNumber = pageNumber, - pageSize = pageSize, - reportingType = reportingType, - seaFronts = seaFronts, - sourcesType = sourcesType, - startedAfterDateTime = startedAfterDateTime, - startedBeforeDateTime = startedBeforeDateTime, - status = status, - ) - .map { ReportingsDataOutput.fromReportingDTO(it) } + pageNumber = pageNumber, + pageSize = pageSize, + reportingType = reportingType, + seaFronts = seaFronts, + sourcesType = sourcesType, + startedAfterDateTime = startedAfterDateTime, + startedBeforeDateTime = startedBeforeDateTime, + status = status, + ) + .map { ReportingsDataOutput.fromReportingDTO(it) } } @PutMapping("", consumes = ["application/json"]) @Operation(summary = "Create a new reporting") @ResponseStatus(HttpStatus.CREATED) fun createReportingController( - @RequestBody createReporting: CreateOrUpdateReportingDataInput, - ): ReportingDetailedDataOutput { + @RequestBody createReporting: CreateOrUpdateReportingDataInput, + ): ReportingDataOutput { val newReporting = createReporting.toReportingEntity() val createdReporting = createOrUpdateReporting.execute(newReporting) return ReportingDataOutput.fromReportingDTO(createdReporting) @@ -97,7 +97,7 @@ class ReportingsController( @GetMapping("/{id}") @Operation(summary = "Get reporting by id") fun getReportingByIdController( - @PathParam("reporting id") @PathVariable(name = "id") id: Int, + @PathParam("reporting id") @PathVariable(name = "id") id: Int, ): ReportingDataOutput { return getReportingById.execute(id).let { ReportingDataOutput.fromReportingDTO(it) } } @@ -105,21 +105,21 @@ class ReportingsController( @PutMapping(value = ["/{id}"], consumes = ["application/json"]) @Operation(summary = "update a reporting") fun updateReportingController( - @PathParam("reporting id") @PathVariable(name = "id") id: Int, - @RequestBody reporting: CreateOrUpdateReportingDataInput, + @PathParam("reporting id") @PathVariable(name = "id") id: Int, + @RequestBody reporting: CreateOrUpdateReportingDataInput, ): ReportingDataOutput { require(id == reporting.id) { "id in path and body must be the same" } return createOrUpdateReporting.execute( - reporting.toReportingEntity(), - ) - .let { ReportingDataOutput.fromReportingDTO(it) } + reporting.toReportingEntity(), + ) + .let { ReportingDataOutput.fromReportingDTO(it) } } @DeleteMapping(value = ["/{id}"]) @Operation(summary = "Delete a reporting") @ResponseStatus(HttpStatus.NO_CONTENT) fun deleteController( - @PathParam("Id") @PathVariable(name = "id") id: Int, + @PathParam("Id") @PathVariable(name = "id") id: Int, ) { deleteReporting.execute(id = id) } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingModel.kt index 58751632f..85d12a6dc 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingModel.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingModel.kt @@ -25,9 +25,6 @@ import jakarta.persistence.Id import jakarta.persistence.JoinColumn import jakarta.persistence.ManyToOne import jakarta.persistence.Table -import java.time.Instant -import java.time.ZoneOffset.UTC -import java.util.UUID import org.hibernate.Hibernate import org.hibernate.annotations.Generated import org.hibernate.annotations.GenerationTime @@ -37,133 +34,136 @@ import org.hibernate.type.descriptor.jdbc.UUIDJdbcType import org.locationtech.jts.geom.Geometry import org.n52.jackson.datatype.jts.GeometryDeserializer import org.n52.jackson.datatype.jts.GeometrySerializer +import java.time.Instant +import java.time.ZoneOffset.UTC +import java.util.UUID @Entity @Table(name = "reportings") data class ReportingModel( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id", unique = true, nullable = false) - val id: Int? = null, - @Generated(GenerationTime.INSERT) - @Column( - name = "reporting_id", - unique = true, - nullable = false, - updatable = false, - insertable = false, - ) - val reportingId: Long? = null, - @Column(name = "source_type", columnDefinition = "reportings_source_type") - @Enumerated(EnumType.STRING) - @Type(PostgreSQLEnumType::class) - val sourceType: SourceTypeEnum? = null, - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "semaphore_id", nullable = true) - @JsonBackReference - val semaphore: SemaphoreModel? = null, - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "control_unit_id", nullable = true) - @JsonBackReference - val controlUnit: ControlUnitModel? = null, - @Column(name = "source_name") val sourceName: String? = null, - @Column(name = "target_type", columnDefinition = "reportings_target_type") - @Enumerated(EnumType.STRING) - @Type(PostgreSQLEnumType::class) - val targetType: TargetTypeEnum? = null, - @Column(name = "vehicle_type", columnDefinition = "reportings_vehicle_type") - @Enumerated(EnumType.STRING) - @Type(PostgreSQLEnumType::class) - val vehicleType: VehicleTypeEnum? = null, - @Column(name = "target_details", columnDefinition = "jsonb") - @Type(JsonBinaryType::class) - val targetDetails: List? = listOf(), - @JsonSerialize(using = GeometrySerializer::class) - @JsonDeserialize(contentUsing = GeometryDeserializer::class) - @Column(name = "geom") - val geom: Geometry? = null, - @Column(name = "sea_front") val seaFront: String? = null, - @Column(name = "description") val description: String? = null, - @Column(name = "report_type", columnDefinition = "reportings_report_type") - @Enumerated(EnumType.STRING) - @Type(PostgreSQLEnumType::class) - val reportType: ReportingTypeEnum? = null, - @Column(name = "theme") val theme: String? = null, - @Column(name = "sub_themes") - @Type(ListArrayType::class) - val subThemes: List? = listOf(), - @Column(name = "action_taken") val actionTaken: String? = null, - @Column(name = "is_control_required") val isControlRequired: Boolean? = null, - @Column(name = "has_no_unit_available") val hasNoUnitAvailable: Boolean? = null, - @Column(name = "created_at") val createdAt: Instant, - @Column(name = "validity_time") val validityTime: Int? = null, - @Column(name = "is_archived", nullable = false) val isArchived: Boolean, - @Column(name = "is_deleted", nullable = false) val isDeleted: Boolean, - @Column(name = "open_by") val openBy: String? = null, - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "mission_id", nullable = true) - @JsonBackReference - val mission: MissionModel? = null, - @Column(name = "attached_to_mission_at_utc") val attachedToMissionAtUtc: Instant? = null, - @Column(name = "detached_from_mission_at_utc") - val detachedFromMissionAtUtc: Instant? = null, - @JdbcType(UUIDJdbcType::class) - @Column(name = "attached_env_action_id", columnDefinition = "uuid") - val attachedEnvActionId: UUID? = null, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", unique = true, nullable = false) + val id: Int? = null, + @Generated(GenerationTime.INSERT) + @Column( + name = "reporting_id", + unique = true, + nullable = false, + updatable = false, + insertable = false, + ) + val reportingId: Long? = null, + @Column(name = "source_type", columnDefinition = "reportings_source_type") + @Enumerated(EnumType.STRING) + @Type(PostgreSQLEnumType::class) + val sourceType: SourceTypeEnum? = null, + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "semaphore_id", nullable = true) + @JsonBackReference + val semaphore: SemaphoreModel? = null, + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "control_unit_id", nullable = true) + @JsonBackReference + val controlUnit: ControlUnitModel? = null, + @Column(name = "source_name") val sourceName: String? = null, + @Column(name = "target_type", columnDefinition = "reportings_target_type") + @Enumerated(EnumType.STRING) + @Type(PostgreSQLEnumType::class) + val targetType: TargetTypeEnum? = null, + @Column(name = "vehicle_type", columnDefinition = "reportings_vehicle_type") + @Enumerated(EnumType.STRING) + @Type(PostgreSQLEnumType::class) + val vehicleType: VehicleTypeEnum? = null, + @Column(name = "target_details", columnDefinition = "jsonb") + @Type(JsonBinaryType::class) + val targetDetails: List? = listOf(), + @JsonSerialize(using = GeometrySerializer::class) + @JsonDeserialize(contentUsing = GeometryDeserializer::class) + @Column(name = "geom") + val geom: Geometry? = null, + @Column(name = "sea_front") val seaFront: String? = null, + @Column(name = "description") val description: String? = null, + @Column(name = "report_type", columnDefinition = "reportings_report_type") + @Enumerated(EnumType.STRING) + @Type(PostgreSQLEnumType::class) + val reportType: ReportingTypeEnum? = null, + @Column(name = "theme") val theme: String? = null, + @Column(name = "sub_themes") + @Type(ListArrayType::class) + val subThemes: List? = listOf(), + @Column(name = "action_taken") val actionTaken: String? = null, + @Column(name = "is_control_required") val isControlRequired: Boolean? = null, + @Column(name = "has_no_unit_available") val hasNoUnitAvailable: Boolean? = null, + @Column(name = "created_at") val createdAt: Instant, + @Column(name = "validity_time") val validityTime: Int? = null, + @Column(name = "is_archived", nullable = false) val isArchived: Boolean, + @Column(name = "is_deleted", nullable = false) val isDeleted: Boolean, + @Column(name = "open_by") val openBy: String? = null, + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "mission_id", nullable = true) + @JsonBackReference + val mission: MissionModel? = null, + @Column(name = "attached_to_mission_at_utc") val attachedToMissionAtUtc: Instant? = null, + @Column(name = "detached_from_mission_at_utc") + val detachedFromMissionAtUtc: Instant? = null, + @JdbcType(UUIDJdbcType::class) + @Column(name = "attached_env_action_id", columnDefinition = "uuid") + val attachedEnvActionId: UUID? = null, ) { fun toReporting() = - ReportingEntity( - id = id, - reportingId = reportingId, - sourceType = sourceType, - semaphoreId = semaphore?.id, - controlUnitId = controlUnit?.id, - sourceName = sourceName, - targetType = targetType, - vehicleType = vehicleType, - targetDetails = targetDetails, - geom = geom, - seaFront = seaFront, - description = description, - reportType = reportType, - theme = theme, - subThemes = subThemes, - actionTaken = actionTaken, - isControlRequired = isControlRequired, - hasNoUnitAvailable = hasNoUnitAvailable, - createdAt = createdAt.atZone(UTC), - validityTime = validityTime, - isArchived = isArchived, - isDeleted = isDeleted, - openBy = openBy, - missionId = mission?.id, - attachedToMissionAtUtc = attachedToMissionAtUtc?.atZone(UTC), - detachedFromMissionAtUtc = detachedFromMissionAtUtc?.atZone(UTC), - attachedEnvActionId = attachedEnvActionId, - ) + ReportingEntity( + id = id, + reportingId = reportingId, + sourceType = sourceType, + semaphoreId = semaphore?.id, + controlUnitId = controlUnit?.id, + sourceName = sourceName, + targetType = targetType, + vehicleType = vehicleType, + targetDetails = targetDetails, + geom = geom, + seaFront = seaFront, + description = description, + reportType = reportType, + theme = theme, + subThemes = subThemes, + actionTaken = actionTaken, + isControlRequired = isControlRequired, + hasNoUnitAvailable = hasNoUnitAvailable, + createdAt = createdAt.atZone(UTC), + validityTime = validityTime, + isArchived = isArchived, + isDeleted = isDeleted, + openBy = openBy, + missionId = mission?.id, + attachedToMissionAtUtc = attachedToMissionAtUtc?.atZone(UTC), + detachedFromMissionAtUtc = detachedFromMissionAtUtc?.atZone(UTC), + attachedEnvActionId = attachedEnvActionId, + ) fun toReportingDTO(objectMapper: ObjectMapper) = - ReportingDTO( - reporting = this.toReporting(), - controlUnit = controlUnit?.toFullControlUnit(), - semaphore = semaphore?.toSemaphore(), - attachedMission = - if (detachedFromMissionAtUtc != null) { - mission?.toMissionEntity( - objectMapper, - ) - } else { - null - }, - detachedMission = - if (detachedFromMissionAtUtc == null) { - mission?.toMissionEntity( - objectMapper, - ) - } else { - null - }, - ) + ReportingDTO( + reporting = this.toReporting(), + controlUnit = controlUnit?.toFullControlUnit(), + semaphore = semaphore?.toSemaphore(), + attachedMission = + if (detachedFromMissionAtUtc != null) { + mission?.toMissionEntity( + objectMapper, + ) + } else { + null + }, + detachedMission = + if (detachedFromMissionAtUtc == null) { + mission?.toMissionEntity( + objectMapper, + ) + } else { + null + }, + ) override fun equals(other: Any?): Boolean { if (this === other) return true @@ -177,39 +177,39 @@ data class ReportingModel( companion object { fun fromReportingEntity( - reporting: ReportingEntity, - semaphoreReference: SemaphoreModel?, - controlUnitReference: ControlUnitModel?, - missionReference: MissionModel?, + reporting: ReportingEntity, + semaphoreReference: SemaphoreModel?, + controlUnitReference: ControlUnitModel?, + missionReference: MissionModel?, ) = - ReportingModel( - id = reporting.id, - reportingId = reporting.reportingId, - sourceType = reporting.sourceType, - semaphore = semaphoreReference, - controlUnit = controlUnitReference, - sourceName = reporting.sourceName, - targetType = reporting.targetType, - vehicleType = reporting.vehicleType, - targetDetails = reporting.targetDetails, - geom = reporting.geom, - seaFront = reporting.seaFront, - description = reporting.description, - reportType = reporting.reportType, - theme = reporting.theme, - subThemes = reporting.subThemes, - actionTaken = reporting.actionTaken, - isControlRequired = reporting.isControlRequired, - hasNoUnitAvailable = reporting.hasNoUnitAvailable, - createdAt = reporting.createdAt.toInstant(), - validityTime = reporting.validityTime, - isArchived = reporting.isArchived, - isDeleted = reporting.isDeleted, - openBy = reporting.openBy, - mission = missionReference, - attachedToMissionAtUtc = reporting.attachedToMissionAtUtc?.toInstant(), - detachedFromMissionAtUtc = reporting.detachedFromMissionAtUtc?.toInstant(), - attachedEnvActionId = reporting.attachedEnvActionId, - ) + ReportingModel( + id = reporting.id, + reportingId = reporting.reportingId, + sourceType = reporting.sourceType, + semaphore = semaphoreReference, + controlUnit = controlUnitReference, + sourceName = reporting.sourceName, + targetType = reporting.targetType, + vehicleType = reporting.vehicleType, + targetDetails = reporting.targetDetails, + geom = reporting.geom, + seaFront = reporting.seaFront, + description = reporting.description, + reportType = reporting.reportType, + theme = reporting.theme, + subThemes = reporting.subThemes, + actionTaken = reporting.actionTaken, + isControlRequired = reporting.isControlRequired, + hasNoUnitAvailable = reporting.hasNoUnitAvailable, + createdAt = reporting.createdAt.toInstant(), + validityTime = reporting.validityTime, + isArchived = reporting.isArchived, + isDeleted = reporting.isDeleted, + openBy = reporting.openBy, + mission = missionReference, + attachedToMissionAtUtc = reporting.attachedToMissionAtUtc?.toInstant(), + detachedFromMissionAtUtc = reporting.detachedFromMissionAtUtc?.toInstant(), + attachedEnvActionId = reporting.attachedEnvActionId, + ) } } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepository.kt index 681e42f2a..cf4c1f686 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepository.kt @@ -12,21 +12,21 @@ import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces. import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBMissionRepository import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBReportingRepository import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBSemaphoreRepository -import java.time.Instant import org.springframework.dao.DataIntegrityViolationException import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.Modifying import org.springframework.orm.jpa.JpaObjectRetrievalFailureException import org.springframework.stereotype.Repository import org.springframework.transaction.annotation.Transactional +import java.time.Instant @Repository class JpaReportingRepository( - private val dbReportingRepository: IDBReportingRepository, - private val dbMissionRepository: IDBMissionRepository, - private val dbSemaphoreRepository: IDBSemaphoreRepository, - private val dbControlUnitRepository: IDBControlUnitRepository, - private val mapper: ObjectMapper, + private val dbReportingRepository: IDBReportingRepository, + private val dbMissionRepository: IDBMissionRepository, + private val dbSemaphoreRepository: IDBSemaphoreRepository, + private val dbControlUnitRepository: IDBControlUnitRepository, + private val mapper: ObjectMapper, ) : IReportingRepository { @Transactional @@ -40,26 +40,26 @@ class JpaReportingRepository( } override fun findAll( - pageable: Pageable, - reportingType: List?, - seaFronts: List?, - sourcesType: List?, - startedAfter: Instant, - startedBefore: Instant?, - status: List?, + pageable: Pageable, + reportingType: List?, + seaFronts: List?, + sourcesType: List?, + startedAfter: Instant, + startedBefore: Instant?, + status: List?, ): List { val sourcesTypeAsStringArray = sourcesType?.map { it.name } val reportingTypeAsStringArray = reportingType?.map { it.name } return dbReportingRepository.findAll( - pageable, - reportingType = convertToString(reportingTypeAsStringArray), - seaFronts = convertToString(seaFronts), - sourcesType = convertToString(sourcesTypeAsStringArray), - startedAfter = startedAfter, - startedBefore = startedBefore, - status = convertToString(status), - ) - .map { it.toReportingDTO(mapper) } + pageable, + reportingType = convertToString(reportingTypeAsStringArray), + seaFronts = convertToString(seaFronts), + sourcesType = convertToString(sourcesTypeAsStringArray), + startedAfter = startedAfter, + startedBefore = startedBefore, + status = convertToString(status), + ) + .map { it.toReportingDTO(mapper) } } override fun findByMissionId(missionId: Int): List { @@ -71,41 +71,41 @@ class JpaReportingRepository( override fun save(reporting: ReportingEntity): ReportingDTO { return try { val semaphoreReference = - if (reporting.semaphoreId != null) { - dbSemaphoreRepository.getReferenceById( - reporting.semaphoreId, - ) - } else { - null - } + if (reporting.semaphoreId != null) { + dbSemaphoreRepository.getReferenceById( + reporting.semaphoreId, + ) + } else { + null + } val controlUnitReference = - if (reporting.controlUnitId != null) { - dbControlUnitRepository.getReferenceById( - reporting.controlUnitId, - ) - } else { - null - } + if (reporting.controlUnitId != null) { + dbControlUnitRepository.getReferenceById( + reporting.controlUnitId, + ) + } else { + null + } val missionReference = - if (reporting.missionId != null) { - dbMissionRepository.getReferenceById( - reporting.missionId, - ) - } else { - null - } - val reportingModel = - ReportingModel.fromReportingEntity( - reporting = reporting, - semaphoreReference = semaphoreReference, - controlUnitReference = controlUnitReference, - missionReference = missionReference, + if (reporting.missionId != null) { + dbMissionRepository.getReferenceById( + reporting.missionId, ) + } else { + null + } + val reportingModel = + ReportingModel.fromReportingEntity( + reporting = reporting, + semaphoreReference = semaphoreReference, + controlUnitReference = controlUnitReference, + missionReference = missionReference, + ) dbReportingRepository.saveAndFlush(reportingModel).toReportingDTO(mapper) } catch (e: JpaObjectRetrievalFailureException) { throw NotFoundException( - "Invalid reference to semaphore, control unit or mission: not found in referential", - e, + "Invalid reference to semaphore, control unit or mission: not found in referential", + e, ) } catch (e: DataIntegrityViolationException) { throw NotFoundException("Invalid combination of mission and/or envAction", e) diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBReportingRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBReportingRepository.kt index 2bbcd72be..6d0ecf921 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBReportingRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBReportingRepository.kt @@ -1,41 +1,41 @@ package fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces import fr.gouv.cacem.monitorenv.infrastructure.database.model.ReportingModel -import java.time.Instant import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Modifying import org.springframework.data.jpa.repository.Query +import java.time.Instant interface IDBReportingRepository : JpaRepository { @Modifying(clearAutomatically = true) @Query( - value = - """ + value = + """ UPDATE reportings SET is_archived = TRUE WHERE (created_at + make_interval(hours => validity_time)) < NOW() AND is_archived IS FALSE """, - nativeQuery = true, + nativeQuery = true, ) fun archiveOutdatedReportings(): Int @Modifying(clearAutomatically = true) @Query( - value = - """ + value = + """ UPDATE reportings SET is_archived = TRUE WHERE id in (:ids) """, - nativeQuery = true, + nativeQuery = true, ) fun archiveReportings(ids: List) @Modifying(clearAutomatically = true) @Query( - value = - """ + value = + """ UPDATE reportings SET mission_id = :missionId, @@ -43,37 +43,37 @@ interface IDBReportingRepository : JpaRepository { detached_from_mission_at_utc = CASE WHEN id not in (:reportingIds) THEN NOW() ELSE CAST(null as timestamp ) END WHERE id in (:reportingIds) or mission_id = :missionId """, - nativeQuery = true, + nativeQuery = true, ) fun attachReportingsToMission(reportingIds: List, missionId: Int) @Modifying(clearAutomatically = true) @Query( - value = - """ + value = + """ UPDATE reportings SET is_deleted = TRUE WHERE id = :id """, - nativeQuery = true, + nativeQuery = true, ) fun delete(id: Int) @Modifying(clearAutomatically = true) @Query( - value = - """ + value = + """ UPDATE reportings SET is_deleted = TRUE WHERE id in (:ids) """, - nativeQuery = true, + nativeQuery = true, ) fun deleteReportings(ids: List) @Query( - value = - """ + value = + """ SELECT * FROM reportings WHERE is_deleted IS FALSE @@ -97,28 +97,28 @@ interface IDBReportingRepository : JpaRepository { ) ORDER BY reporting_id DESC """, - nativeQuery = true, + nativeQuery = true, ) fun findAll( - pageable: Pageable, - reportingType: String?, - seaFronts: String?, - sourcesType: String?, - startedAfter: Instant, - startedBefore: Instant?, - status: String?, + pageable: Pageable, + reportingType: String?, + seaFronts: String?, + sourcesType: String?, + startedAfter: Instant, + startedBefore: Instant?, + status: String?, ): List @Query( - value = - """ + value = + """ SELECT * FROM reportings WHERE mission_id = :missionId """, - nativeQuery = true, + nativeQuery = true, ) fun findByMissionId( - missionId: Int, + missionId: Int, ): List } diff --git a/frontend/src/api/api.ts b/frontend/src/api/api.ts index fc5a055af..0ea9d60ea 100644 --- a/frontend/src/api/api.ts +++ b/frontend/src/api/api.ts @@ -27,7 +27,7 @@ export const monitorenvPrivateApi = createApi({ }, endpoints: () => ({}), reducerPath: 'monitorenvPrivateApi', - tagTypes: [] + tagTypes: ['Missions', 'Reportings'] }) // ============================================================================= diff --git a/frontend/src/api/missionsAPI.ts b/frontend/src/api/missionsAPI.ts index 3b46ba65f..06caa8cf3 100644 --- a/frontend/src/api/missionsAPI.ts +++ b/frontend/src/api/missionsAPI.ts @@ -1,6 +1,6 @@ -import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' +import { monitorenvPrivateApi } from './api' -import type { Mission } from '../domain/entities/missions' +import type { Mission, MissionForApi } from '../domain/entities/missions' type MissionsResponse = Mission[] type MissionsFilter = { @@ -24,29 +24,31 @@ const getMissionTypesFilter = missionTypes => const getSeaFrontsFilter = seaFronts => seaFronts && seaFronts?.length > 0 && `seaFronts=${encodeURIComponent(seaFronts)}` -export const missionsAPI = createApi({ - baseQuery: fetchBaseQuery({ baseUrl: '/bff/v1' }), - endpoints: build => ({ - createMission: build.mutation>({ - invalidatesTags: [{ id: 'LIST', type: 'Missions' }], +export const missionsAPI = monitorenvPrivateApi.injectEndpoints({ + endpoints: builder => ({ + createMission: builder.mutation({ + invalidatesTags: [ + { id: 'LIST', type: 'Missions' }, + { id: 'LIST', type: 'Reportings' } + ], query: mission => ({ body: mission, method: 'PUT', url: `missions` }) }), - deleteMission: build.mutation({ + deleteMission: builder.mutation({ invalidatesTags: [{ id: 'LIST', type: 'Missions' }], query: ({ id }) => ({ method: 'DELETE', url: `missions/${id}` }) }), - getMission: build.query({ + getMission: builder.query({ providesTags: (_, __, id) => [{ id, type: 'Missions' }], query: id => `missions/${id}` }), - getMissions: build.query({ + getMissions: builder.query({ providesTags: result => result ? // successful query @@ -66,7 +68,7 @@ export const missionsAPI = createApi({ .filter(v => v) .join('&') }), - updateMission: build.mutation({ + updateMission: builder.mutation({ invalidatesTags: (_, __, { id }) => [ { id, type: 'Missions' }, { id: 'LIST', type: 'Missions' } @@ -78,9 +80,7 @@ export const missionsAPI = createApi({ url: `missions/${id}` }) }) - }), - reducerPath: 'missions', - tagTypes: ['Missions'] + }) }) export const { diff --git a/frontend/src/api/reportingsAPI.ts b/frontend/src/api/reportingsAPI.ts index 265cc4f76..4c3fda7b8 100644 --- a/frontend/src/api/reportingsAPI.ts +++ b/frontend/src/api/reportingsAPI.ts @@ -1,6 +1,6 @@ import { type EntityState, createEntityAdapter } from '@reduxjs/toolkit' -import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' +import { monitorenvPrivateApi } from './api' import { getQueryString } from '../utils/getQueryStringFormatted' import type { Reporting, ReportingDetailed } from '../domain/entities/reporting' @@ -17,8 +17,7 @@ type ReportingsFilter = { const ReportingAdapter = createEntityAdapter() const initialState = ReportingAdapter.getInitialState() -export const reportingsAPI = createApi({ - baseQuery: fetchBaseQuery({ baseUrl: '/bff/v1' }), +export const reportingsAPI = monitorenvPrivateApi.injectEndpoints({ endpoints: build => ({ archiveReportings: build.mutation({ invalidatesTags: (_, __, results) => @@ -32,7 +31,10 @@ export const reportingsAPI = createApi({ }) }), createReporting: build.mutation, Partial>({ - invalidatesTags: [{ id: 'LIST', type: 'Reportings' }], + invalidatesTags: [ + { id: 'LIST', type: 'Reportings' }, + { id: 'LIST', type: 'Missions' } + ], query: reporting => ({ body: reporting, method: 'PUT', @@ -80,9 +82,7 @@ export const reportingsAPI = createApi({ url: `reportings/${id}` }) }) - }), - reducerPath: 'reportings', - tagTypes: ['Reportings'] + }) }) export const { diff --git a/frontend/src/domain/entities/missions.ts b/frontend/src/domain/entities/missions.ts index 8fe4c5038..60940530b 100644 --- a/frontend/src/domain/entities/missions.ts +++ b/frontend/src/domain/entities/missions.ts @@ -276,6 +276,7 @@ export type NewMission = Omit & { controlUnits: Array> } +export type MissionForApi = Omit, 'attachedReportings'> export type EnvAction = EnvActionControl | EnvActionSurveillance | EnvActionNote export type NewEnvAction = NewEnvActionControl | EnvActionSurveillance | EnvActionNote diff --git a/frontend/src/domain/entities/reporting.ts b/frontend/src/domain/entities/reporting.ts index d3a27a88a..9a53d885b 100644 --- a/frontend/src/domain/entities/reporting.ts +++ b/frontend/src/domain/entities/reporting.ts @@ -8,17 +8,17 @@ export type Reporting = { actionTaken?: string attachedEnvActionId?: string attachedMission?: Mission - attachedMissionId?: number attachedToMissionAtUtc?: string controlUnitId?: number createdAt: string description?: string detachedFromMissionAtUtc?: string geom: Record[] + hasNoUnitAvailable?: boolean | undefined id: number | string isArchived?: boolean isControlRequired?: boolean | undefined - isUnitAvailable?: boolean | undefined + missionId?: number openBy: string reportType: ReportingTypeEnum reportingId?: number diff --git a/frontend/src/domain/shared_slices/index.ts b/frontend/src/domain/shared_slices/index.ts deleted file mode 100644 index d2a41524c..000000000 --- a/frontend/src/domain/shared_slices/index.ts +++ /dev/null @@ -1,94 +0,0 @@ -// TODO We should move that into `/frontend/src/store` directory. - -import { combineReducers } from '@reduxjs/toolkit' - -import { administrativeSlicePersistedReducer } from './Administrative' -import { drawReducer } from './Draw' -import { globalReducer } from './Global' -import { interestPointSlicePersistedReducer } from './InterestPoint' -import { layerSidebarSlice } from './LayerSidebar' -import { mapSliceReducer } from './Map' -import { measurementSlicePersistedReducer } from './Measurement' -import { missionFiltersPersistedReducer } from './MissionFilters' -import { missionStateSliceReducer } from './MissionsState' -import { multiMissionsSliceReducer } from './MultiMissions' -import { regulatorySlicePersistedReducer } from './Regulatory' -import { regulatoryMetadataSliceReducer } from './RegulatoryMetadata' -import { reportingSliceReducer } from './reporting' -import { reportingFiltersPersistedReducer } from './ReportingsFilters' -import { selectedAmpSlicePersistedReducer } from './SelectedAmp' -import { semaphoresPersistedReducer } from './SemaphoresSlice' -import { ampsAPI, ampsErrorLoggerMiddleware } from '../../api/ampsAPI' -import { monitorenvPrivateApi, monitorenvPublicApi } from '../../api/api' -import { controlThemesAPI } from '../../api/controlThemesAPI' -import { infractionsAPI } from '../../api/infractionsAPI' -import { legacyControlUnitsAPI } from '../../api/legacyControlUnitsAPI' -import { missionsAPI } from '../../api/missionsAPI' -import { regulatoryLayersAPI } from '../../api/regulatoryLayersAPI' -import { reportingsAPI } from '../../api/reportingsAPI' -import { semaphoresAPI } from '../../api/semaphoresAPI' -import { administrationTablePersistedReducer } from '../../features/Administration/components/AdministrationTable/slice' -import { backOfficeReducer } from '../../features/BackOffice/slice' -import { baseTablePersistedReducer } from '../../features/Base/components/BaseTable/slice' -import { controlUnitDialogReducer } from '../../features/ControlUnit/components/ControlUnitDialog/slice' -import { controlUnitListDialogPersistedReducer } from '../../features/ControlUnit/components/ControlUnitListDialog/slice' -import { controlUnitTablePersistedReducer } from '../../features/ControlUnit/components/ControlUnitTable/slice' -import { layerSearchSliceReducer } from '../../features/layersSelector/search/slice' -import { mainWindowReducer } from '../../features/MainWindow/slice' -import { attachReportingToMissionsSliceReducer } from '../../features/missions/MissionForm/AttachReporting/slice' -import { attachMissionToReportingSliceReducer } from '../../features/Reportings/ReportingForm/AttachMission/slice' -import { sideWindowReducer } from '../../features/SideWindow/slice' - -// TODO Maybe add a specifc store for the backoffice? -// But it won't be necessarily cleaner since current APIs are also needed in the home anyway. -export const homeReducers = combineReducers({ - [monitorenvPrivateApi.reducerPath]: monitorenvPrivateApi.reducer, - [monitorenvPublicApi.reducerPath]: monitorenvPublicApi.reducer, - administrative: administrativeSlicePersistedReducer, - attachMissionToReporting: attachMissionToReportingSliceReducer, - attachReportingToMission: attachReportingToMissionsSliceReducer, - backOffice: backOfficeReducer, - backOfficeAdministrationList: administrationTablePersistedReducer, - backOfficeBaseList: baseTablePersistedReducer, - backOfficeControlUnitList: controlUnitTablePersistedReducer, - draw: drawReducer, - global: globalReducer, - interestPoint: interestPointSlicePersistedReducer, - layerSearch: layerSearchSliceReducer, - mainWindow: mainWindowReducer, - map: mapSliceReducer, - mapControlUnitDialog: controlUnitDialogReducer, - mapControlUnitListDialog: controlUnitListDialogPersistedReducer, - measurement: measurementSlicePersistedReducer, - missionFilters: missionFiltersPersistedReducer, - missionState: missionStateSliceReducer, - multiMissions: multiMissionsSliceReducer, - regulatory: regulatorySlicePersistedReducer, - regulatoryMetadata: regulatoryMetadataSliceReducer, - [layerSidebarSlice.name]: layerSidebarSlice.reducer, - [ampsAPI.reducerPath]: ampsAPI.reducer, - [regulatoryLayersAPI.reducerPath]: regulatoryLayersAPI.reducer, - [missionsAPI.reducerPath]: missionsAPI.reducer, - [controlThemesAPI.reducerPath]: controlThemesAPI.reducer, - [legacyControlUnitsAPI.reducerPath]: legacyControlUnitsAPI.reducer, - [infractionsAPI.reducerPath]: infractionsAPI.reducer, - [semaphoresAPI.reducerPath]: semaphoresAPI.reducer, - reporting: reportingSliceReducer, - [reportingsAPI.reducerPath]: reportingsAPI.reducer, - reportingFilters: reportingFiltersPersistedReducer, - selectedAmp: selectedAmpSlicePersistedReducer, - semaphoresSlice: semaphoresPersistedReducer, - sideWindow: sideWindowReducer -}) - -export const homeMiddlewares = [ - ampsAPI.middleware, - ampsErrorLoggerMiddleware, - missionsAPI.middleware, - regulatoryLayersAPI.middleware, - controlThemesAPI.middleware, - legacyControlUnitsAPI.middleware, - infractionsAPI.middleware, - semaphoresAPI.middleware, - reportingsAPI.middleware -] diff --git a/frontend/src/domain/use_cases/missions/attachReportingFromMap.ts b/frontend/src/domain/use_cases/missions/attachReportingFromMap.ts index 0513c892f..1599df1cc 100644 --- a/frontend/src/domain/use_cases/missions/attachReportingFromMap.ts +++ b/frontend/src/domain/use_cases/missions/attachReportingFromMap.ts @@ -20,7 +20,7 @@ export const attachReportingFromMap = (id: number) => async (dispatch, getState) ...attachedReportings, { ...response.data, - attachedMissionId: missionId + missionId } ]) ) diff --git a/frontend/src/domain/use_cases/missions/saveMission.ts b/frontend/src/domain/use_cases/missions/saveMission.ts index b3b82e638..ccc83006c 100644 --- a/frontend/src/domain/use_cases/missions/saveMission.ts +++ b/frontend/src/domain/use_cases/missions/saveMission.ts @@ -1,3 +1,5 @@ +import omit from 'lodash/omit' + import { missionsAPI } from '../../../api/missionsAPI' import { sideWindowActions } from '../../../features/SideWindow/slice' import { isNewMission } from '../../../utils/isNewMission' @@ -13,10 +15,11 @@ export const saveMission = const { sideWindow: { currentPath } } = getState() + const valuesToSave = omit(values, ['attachedReportings']) const routeParams = getMissionPageRoute(currentPath) const missionIsNewMission = isNewMission(routeParams?.params?.id) - const cleanValues = missionIsNewMission ? { ...values, id: undefined } : values + const cleanValues = missionIsNewMission ? { ...valuesToSave, id: undefined } : valuesToSave const upsertMission = missionIsNewMission ? missionsAPI.endpoints.createMission : missionsAPI.endpoints.updateMission diff --git a/frontend/src/domain/use_cases/reporting/saveReporting.ts b/frontend/src/domain/use_cases/reporting/saveReporting.ts index 481abd222..0c8232a95 100644 --- a/frontend/src/domain/use_cases/reporting/saveReporting.ts +++ b/frontend/src/domain/use_cases/reporting/saveReporting.ts @@ -1,3 +1,5 @@ +import omit from 'lodash/omit' + import { reportingsAPI } from '../../../api/reportingsAPI' import { isNewReporting } from '../../../features/Reportings/utils' import { setReportingFormVisibility, setToast, ReportingContext, VisibilityState } from '../../shared_slices/Global' @@ -8,7 +10,8 @@ import type { Reporting } from '../../entities/reporting' export const saveReporting = (values: Reporting | Partial, reportingContext: ReportingContext) => async dispatch => { - const cleanValues = isNewReporting(values.id) ? { ...values, id: undefined } : values + const valuesToSave = omit(values, ['attachedMission']) + const cleanValues = isNewReporting(valuesToSave.id) ? { ...valuesToSave, id: undefined } : valuesToSave const endpoint = isNewReporting(values.id) ? reportingsAPI.endpoints.createReporting : reportingsAPI.endpoints.updateReporting diff --git a/frontend/src/features/Reportings/Layers/MissionToAttach/SelectedMissionToAttachLayer.tsx b/frontend/src/features/Reportings/Layers/MissionToAttach/SelectedMissionToAttachLayer.tsx index 78c52c35c..a6ba5613e 100644 --- a/frontend/src/features/Reportings/Layers/MissionToAttach/SelectedMissionToAttachLayer.tsx +++ b/frontend/src/features/Reportings/Layers/MissionToAttach/SelectedMissionToAttachLayer.tsx @@ -13,10 +13,10 @@ import type { BaseMapChildrenProps } from '../../../map/BaseMap' export function SelectedMissionToAttachLayer({ map }: BaseMapChildrenProps) { const attachMissionListener = useAppSelector(state => state.attachMissionToReporting.attachMissionListener) - const attachedMissionId = useAppSelector(state => state.attachMissionToReporting.attachedMissionId) + const missionId = useAppSelector(state => state.attachMissionToReporting.missionId) const { selectedMission: attachedMission } = useGetMissionsQuery(undefined, { selectFromResult: ({ data }) => ({ - selectedMission: data?.find(op => op.id === attachedMissionId) + selectedMission: data?.find(op => op.id === missionId) }) }) const selectedAttachedMissionVectorSourceRef = useRef() as MutableRefObject @@ -62,8 +62,8 @@ export function SelectedMissionToAttachLayer({ map }: BaseMapChildrenProps) { }, [map, GetSelectedMissionVectorLayer]) useEffect(() => { - GetSelectedMissionVectorLayer()?.setVisible(!!attachedMissionId && attachMissionListener) - }, [attachedMissionId, attachMissionListener, GetSelectedMissionVectorLayer]) + GetSelectedMissionVectorLayer()?.setVisible(!!missionId && attachMissionListener) + }, [missionId, attachMissionListener, GetSelectedMissionVectorLayer]) useEffect(() => { GetSelectedMissionVectorSource()?.clear(true) diff --git a/frontend/src/features/Reportings/Layers/MissionToAttach/index.tsx b/frontend/src/features/Reportings/Layers/MissionToAttach/index.tsx index 69f452d28..89f430f7d 100644 --- a/frontend/src/features/Reportings/Layers/MissionToAttach/index.tsx +++ b/frontend/src/features/Reportings/Layers/MissionToAttach/index.tsx @@ -1,10 +1,10 @@ import VectorLayer from 'ol/layer/Vector' import VectorSource from 'ol/source/Vector' import { useCallback, useEffect, useMemo, useRef } from 'react' -import { useDispatch } from 'react-redux' import { useGetMissionsQuery } from '../../../../api/missionsAPI' import { Layers } from '../../../../domain/entities/layers/constants' +import { useAppDispatch } from '../../../../hooks/useAppDispatch' import { useAppSelector } from '../../../../hooks/useAppSelector' import { getMissionZoneFeature } from '../../../map/layers/Missions/missionGeometryHelpers' import { missionWithCentroidStyleFn } from '../../../map/layers/Missions/missions.style' @@ -14,7 +14,7 @@ import type { BaseMapChildrenProps } from '../../../map/BaseMap' import type { Geometry } from 'ol/geom' export function MissionToAttachLayer({ map, mapClickEvent }: BaseMapChildrenProps) { - const dispatch = useDispatch() + const dispatch = useAppDispatch() const attachMissionListener = useAppSelector(state => state.attachMissionToReporting.attachMissionListener) const { data: missions } = useGetMissionsQuery({ missionStatus: ['PENDING'] @@ -78,7 +78,7 @@ export function MissionToAttachLayer({ map, mapClickEvent }: BaseMapChildrenProp const feature = mapClickEvent?.feature if (feature.getId()?.toString()?.includes(Layers.MISSION_TO_ATTACH_ON_REPORTING.code)) { const { missionId } = feature.getProperties() - dispatch(attachMissionToReportingSliceActions.setAttachedMissionId(missionId)) + dispatch(attachMissionToReportingSliceActions.setMissionId(missionId)) } } }, [dispatch, mapClickEvent]) diff --git a/frontend/src/features/Reportings/Overlays/MissionToAttach/index.tsx b/frontend/src/features/Reportings/Overlays/MissionToAttach/index.tsx new file mode 100644 index 000000000..c3227d1db --- /dev/null +++ b/frontend/src/features/Reportings/Overlays/MissionToAttach/index.tsx @@ -0,0 +1,24 @@ +import { Layers } from '../../../../domain/entities/layers/constants' +import { useAppSelector } from '../../../../hooks/useAppSelector' +import { MissionCard } from '../../../map/overlays/missions/MissionCard' +import { OverlayPositionOnExtent } from '../../../map/overlays/OverlayPositionOnExtent' + +import type { BaseMapChildrenProps } from '../../../map/BaseMap' + +export function MissionToAttachOverlays({ currentFeatureOver, map }: BaseMapChildrenProps) { + const { displayMissionToAttachLayer } = useAppSelector(state => state.global) + + const currentfeatureId = currentFeatureOver?.getId() + const displayHoveredFeature = + typeof currentfeatureId === 'string' && currentfeatureId.startsWith(Layers.MISSION_TO_ATTACH_ON_REPORTING.code) + + return ( + + + + ) +} diff --git a/frontend/src/features/Reportings/ReportingForm/AttachMission/AttachMissionToReportingModal.tsx b/frontend/src/features/Reportings/ReportingForm/AttachMission/AttachMissionToReportingModal.tsx index 21e94cf51..9b9000f17 100644 --- a/frontend/src/features/Reportings/ReportingForm/AttachMission/AttachMissionToReportingModal.tsx +++ b/frontend/src/features/Reportings/ReportingForm/AttachMission/AttachMissionToReportingModal.tsx @@ -14,8 +14,11 @@ export function AttachMissionToReportingModal() { const attachMissionListener = useAppSelector(state => state.attachMissionToReporting.attachMissionListener) const initialAttachedMission = useAppSelector(state => state.attachMissionToReporting.initialAttachedMission) + const initialMissionId = useAppSelector(state => state.attachMissionToReporting.initialMissionId) + const resetMissionToAttach = () => { dispatch(attachMissionToReportingSliceActions.setAttachedMission(initialAttachedMission)) + dispatch(attachMissionToReportingSliceActions.setMissionId(initialMissionId)) } const validateMissionToAttach = () => { diff --git a/frontend/src/features/Reportings/ReportingForm/AttachMission/index.tsx b/frontend/src/features/Reportings/ReportingForm/AttachMission/index.tsx index d668c9dbd..c814283fb 100644 --- a/frontend/src/features/Reportings/ReportingForm/AttachMission/index.tsx +++ b/frontend/src/features/Reportings/ReportingForm/AttachMission/index.tsx @@ -19,13 +19,10 @@ import type { Reporting } from '../../../../domain/entities/reporting' export function AttachMission({ setIsAttachNewMission }) { const { handleSubmit, setFieldValue, values } = useFormikContext() const dispatch = useAppDispatch() - const attachedMissionId = useAppSelector(state => state.attachMissionToReporting.attachedMissionId) + const missionId = useAppSelector(state => state.attachMissionToReporting.missionId) - const hasMissionAttached = - !!values.attachedMissionId && !!values.attachedMission && values.attachedMission.id === attachedMissionId - const { data: missionToAttach } = useGetMissionQuery( - !hasMissionAttached && attachedMissionId ? attachedMissionId : skipToken - ) + const hasMissionAttached = !!values.missionId && !!values.attachedMission && values.attachedMission.id === missionId + const { data: missionToAttach } = useGetMissionQuery(!hasMissionAttached && missionId ? missionId : skipToken) const attachMission = () => { dispatch(attachMissionToReportingSliceActions.setInitialAttachedMission(values.attachedMission)) @@ -33,7 +30,7 @@ export function AttachMission({ setIsAttachNewMission }) { } const unattachMission = () => { - dispatch(attachMissionToReportingSliceActions.setAttachedMissionId(undefined)) + dispatch(attachMissionToReportingSliceActions.setMissionId(undefined)) dispatch(attachMissionToReportingSliceActions.setAttachedMission(undefined)) } @@ -43,13 +40,13 @@ export function AttachMission({ setIsAttachNewMission }) { } useEffect(() => { - if (attachedMissionId !== values.attachedMissionId && missionToAttach) { - setFieldValue('attachedMissionId', attachedMissionId) - setFieldValue('attachedMission', attachedMissionId ? missionToAttach : undefined) + if (missionId !== values.missionId && missionToAttach) { + setFieldValue('missionId', missionId) + setFieldValue('attachedMission', missionId ? missionToAttach : undefined) } - }, [attachedMissionId, setFieldValue, dispatch, missionToAttach, values.attachedMissionId]) + }, [missionId, setFieldValue, dispatch, missionToAttach, values.missionId]) - return !values.attachedMissionId ? ( + return !values.missionId ? ( - + ) : (
diff --git a/frontend/src/features/Reportings/ReportingForm/AttachMission/slice.ts b/frontend/src/features/Reportings/ReportingForm/AttachMission/slice.ts index 411a56b7f..3b495a32f 100644 --- a/frontend/src/features/Reportings/ReportingForm/AttachMission/slice.ts +++ b/frontend/src/features/Reportings/ReportingForm/AttachMission/slice.ts @@ -5,17 +5,17 @@ import type { Mission } from '../../../../domain/entities/missions' type AttachMissionToReportingSliceState = { attachMissionListener: boolean attachedMission: Mission | undefined - attachedMissionId: number | undefined initialAttachedMission: Mission | undefined - initialAttachedMissionId: number | undefined + initialMissionId: number | undefined + missionId: number | undefined } const initialState: AttachMissionToReportingSliceState = { attachedMission: undefined, - attachedMissionId: undefined, attachMissionListener: false, initialAttachedMission: undefined, - initialAttachedMissionId: undefined + initialMissionId: undefined, + missionId: undefined } const attachMissionToReportingSlice = createSlice({ @@ -28,15 +28,15 @@ const attachMissionToReportingSlice = createSlice({ setAttachedMission(state, action) { state.attachedMission = action.payload }, - setAttachedMissionId(state, action) { - state.attachedMissionId = action.payload - }, setAttachMissionListener(state, action) { state.attachMissionListener = action.payload }, setInitialAttachedMission(state, action: PayloadAction) { - state.initialAttachedMissionId = action.payload?.id + state.initialMissionId = action.payload?.id state.initialAttachedMission = action.payload + }, + setMissionId(state, action) { + state.missionId = action.payload } } }) diff --git a/frontend/src/features/Reportings/ReportingsList/Cells/CellActionStatus.tsx b/frontend/src/features/Reportings/ReportingsList/Cells/CellActionStatus.tsx index 925231990..545cc4dde 100644 --- a/frontend/src/features/Reportings/ReportingsList/Cells/CellActionStatus.tsx +++ b/frontend/src/features/Reportings/ReportingsList/Cells/CellActionStatus.tsx @@ -2,14 +2,14 @@ import { StatusActionTag } from '../../components/StatusActionTag' export function CellActionStatus({ attachedEnvActionId, - attachedMissionId, - isControlRequired + isControlRequired, + missionId }: { attachedEnvActionId: string - attachedMissionId: string isControlRequired: boolean + missionId: string }) { - if (!attachedMissionId || !isControlRequired) { + if (!missionId || !isControlRequired) { return null } diff --git a/frontend/src/features/Reportings/ReportingsList/Cells/CellAttachedToMission.tsx b/frontend/src/features/Reportings/ReportingsList/Cells/CellAttachedToMission.tsx index 0dd443d66..3897602e9 100644 --- a/frontend/src/features/Reportings/ReportingsList/Cells/CellAttachedToMission.tsx +++ b/frontend/src/features/Reportings/ReportingsList/Cells/CellAttachedToMission.tsx @@ -1,7 +1,7 @@ import { LinkToMissionTag } from '../../components/LinkToMissionTag' -export function CellAttachedtoMission({ attachedMissionId }: { attachedMissionId: number }) { - if (!attachedMissionId) { +export function CellAttachedtoMission({ missionId }: { missionId: number }) { + if (!missionId) { return null } diff --git a/frontend/src/features/Reportings/ReportingsList/Columns/index.tsx b/frontend/src/features/Reportings/ReportingsList/Columns/index.tsx index 2d5e1f0ff..72443ce11 100644 --- a/frontend/src/features/Reportings/ReportingsList/Columns/index.tsx +++ b/frontend/src/features/Reportings/ReportingsList/Columns/index.tsx @@ -115,11 +115,11 @@ export const Columns = [ } }, { - accessorFn: row => row.attachedMissionId, - cell: info => , + accessorFn: row => row.missionId, + cell: info => , enableSorting: false, header: () => '', - id: 'attachedMissionId', + id: 'missionId', size: 155 }, { @@ -127,8 +127,8 @@ export const Columns = [ cell: ({ row }) => ( ), enableSorting: false, diff --git a/frontend/src/features/Reportings/hooks/useSyncFormValuesWithRedux.ts b/frontend/src/features/Reportings/hooks/useSyncFormValuesWithRedux.ts index 7da5fbe36..c27cadbcd 100644 --- a/frontend/src/features/Reportings/hooks/useSyncFormValuesWithRedux.ts +++ b/frontend/src/features/Reportings/hooks/useSyncFormValuesWithRedux.ts @@ -20,8 +20,8 @@ export const useSyncFormValuesWithRedux = () => { } dispatch(reportingActions.setReportingState(newValues)) dispatch(reportingActions.setIsDirty(newValues ? dirty : false)) - dispatch(attachMissionToReportingSliceActions.setAttachedMissionId(newValues?.attachedMissionId)) - dispatch(attachMissionToReportingSliceActions.setAttachedMission(newValues?.attachedMission)) + dispatch(attachMissionToReportingSliceActions.setMissionId(newValues?.missionId)) + dispatch(attachMissionToReportingSliceActions.setAttachedMission(newValues?.missionId)) } return _.throttle(throttled, 500) diff --git a/frontend/src/features/Reportings/utils.tsx b/frontend/src/features/Reportings/utils.tsx index fa6bfa8dc..4cb4065b5 100644 --- a/frontend/src/features/Reportings/utils.tsx +++ b/frontend/src/features/Reportings/utils.tsx @@ -45,7 +45,7 @@ export const getReportingTitle = reporting => { return Archivé } - if (reporting.attachedMissionId) { + if (reporting.missionId) { return } diff --git a/frontend/src/features/map/layers/Reportings/reportingsGeometryHelpers.ts b/frontend/src/features/map/layers/Reportings/reportingsGeometryHelpers.ts index bac6e416f..e241ea14b 100644 --- a/frontend/src/features/map/layers/Reportings/reportingsGeometryHelpers.ts +++ b/frontend/src/features/map/layers/Reportings/reportingsGeometryHelpers.ts @@ -20,7 +20,6 @@ export const getReportingZoneFeature = (reporting: ReportingDetailed, layername: actionTaken: reporting.actionTaken, attachedEnvActionId: reporting.attachedEnvActionId, attachedMission: reporting.attachedMission, - attachedMissionId: reporting.attachedMissionId, controlUnitId: reporting.controlUnitId, createdAt: reporting.createdAt, description: reporting.description, @@ -28,6 +27,7 @@ export const getReportingZoneFeature = (reporting: ReportingDetailed, layername: geom: reporting.geom, id: reporting.id, isArchived: reporting.isArchived, + missionId: reporting.missionId, reportingId: reporting.reportingId, reportType: reporting.reportType, semaphoreId: reporting.semaphoreId, @@ -55,13 +55,13 @@ export const getEditingReportingZoneFeature = (reporting: Reporting, layername: actionTaken: reporting.actionTaken, attachedEnvActionId: reporting.attachedEnvActionId, attachedMission: reporting.attachedMission, - attachedMissionId: reporting.attachedMissionId, controlUnitId: reporting.controlUnitId, createdAt: reporting.createdAt, description: reporting.description, geom: reporting.geom, id: reporting.id, isArchived: reporting.isArchived, + missionId: reporting.missionId, reportingId: reporting.reportingId, reportType: reporting.reportType, semaphoreId: reporting.semaphoreId, diff --git a/frontend/src/features/map/layers/Reportings/style.ts b/frontend/src/features/map/layers/Reportings/style.ts index 5407b12ca..0a52d7e0e 100644 --- a/frontend/src/features/map/layers/Reportings/style.ts +++ b/frontend/src/features/map/layers/Reportings/style.ts @@ -89,7 +89,7 @@ export const hoveredReportingStyleFn = feature => { validityTime: feature.get('validityTime') }) - if (feature.get('attachedMissionId')) { + if (feature.get('missionId')) { if (status === ReportingStatusEnum.ARCHIVED) { return hoveredReportingZoneStyleFactory(THEME.color.mediumSeaGreen, getColorWithAlpha(THEME.color.white, 0.2)) } @@ -125,7 +125,7 @@ export const selectedReportingStyleFn = feature => { validityTime: feature.get('validityTime') }) - if (feature.get('attachedMissionId')) { + if (feature.get('missionId')) { if (status === ReportingStatusEnum.ARCHIVED) { return selectedReportingStyleFactory(THEME.color.mediumSeaGreen, getColorWithAlpha(THEME.color.white, 0.25)) } @@ -163,7 +163,7 @@ export const reportingPinStyleFn = feature => { validityTime: feature.get('validityTime') }) - if (feature.get('attachedMissionId')) { + if (feature.get('missionId')) { if (status === ReportingStatusEnum.ARCHIVED) { return reportingStyleFactory(THEME.color.white, 'archived_reporting_with_mission_attached.svg') } @@ -192,8 +192,8 @@ export const reportingPinStyleFn = feature => { const reportingToMissionLinkStyle = feature => new Style({ geometry: () => { - const attachedMissionId = feature.get('attachedMissionId') - if (!attachedMissionId) { + const missionId = feature.get('missionId') + if (!missionId) { return undefined } const reportingExtent = feature?.getGeometry()?.getExtent() diff --git a/frontend/src/features/map/overlays/reportings/ReportingCard.tsx b/frontend/src/features/map/overlays/reportings/ReportingCard.tsx index cbae6e525..eb7c1d2bc 100644 --- a/frontend/src/features/map/overlays/reportings/ReportingCard.tsx +++ b/frontend/src/features/map/overlays/reportings/ReportingCard.tsx @@ -71,12 +71,12 @@ export function ReportingCard({ const { attachedEnvActionId, - attachedMissionId, createdAt, description, displayedSource, id, isArchived, + missionId, reportingId, reportType, subThemes, @@ -166,7 +166,7 @@ export function ReportingCard({ {!isOnlyHoverable && ( diff --git a/frontend/src/features/missions/Layers/ReportingToAttach/index.tsx b/frontend/src/features/missions/Layers/ReportingToAttach/index.tsx index 63f1c766f..e6fb45e97 100644 --- a/frontend/src/features/missions/Layers/ReportingToAttach/index.tsx +++ b/frontend/src/features/missions/Layers/ReportingToAttach/index.tsx @@ -2,12 +2,12 @@ import { reduce } from 'lodash' import VectorLayer from 'ol/layer/Vector' import VectorSource from 'ol/source/Vector' import { useCallback, useEffect, useMemo, useRef } from 'react' -import { useDispatch } from 'react-redux' import { useGetReportingsQuery } from '../../../../api/reportingsAPI' import { Layers } from '../../../../domain/entities/layers/constants' import { StatusFilterEnum } from '../../../../domain/entities/reporting' import { attachReportingFromMap } from '../../../../domain/use_cases/missions/attachReportingFromMap' +import { useAppDispatch } from '../../../../hooks/useAppDispatch' import { useAppSelector } from '../../../../hooks/useAppSelector' import { getReportingZoneFeature } from '../../../map/layers/Reportings/reportingsGeometryHelpers' import { reportingPinStyleFn } from '../../../map/layers/Reportings/style' @@ -17,7 +17,7 @@ import type { Feature } from 'ol' import type { Geometry } from 'ol/geom' export function ReportingToAttachLayer({ map, mapClickEvent }: BaseMapChildrenProps) { - const dispatch = useDispatch() + const dispatch = useAppDispatch() const attachReportingListener = useAppSelector(state => state.attachReportingToMission.attachReportingListener) const attachedReportings = useAppSelector(state => state.attachReportingToMission.attachedReportings) diff --git a/frontend/src/features/missions/MissionForm/mission.json b/frontend/src/features/missions/MissionForm/mission.json index ccf4bb43e..8de54d7b3 100644 --- a/frontend/src/features/missions/MissionForm/mission.json +++ b/frontend/src/features/missions/MissionForm/mission.json @@ -149,7 +149,7 @@ "subThemes": null, "actionTaken": null, "isControlRequired": true, - "isUnitAvailable": true, + "hasNoUnitAvailable": true, "createdAt": "2023-09-25T15:17:32.847553Z", "validityTime": 6, "isArchived": false, @@ -197,7 +197,7 @@ "subThemes": ["Braconnage"], "actionTaken": null, "isControlRequired": true, - "isUnitAvailable": true, + "hasNoUnitAvailable": true, "createdAt": "2023-09-25T13:17:32.847553Z", "validityTime": 4, "isArchived": false, @@ -244,7 +244,7 @@ "subThemes": ["ZMEL"], "actionTaken": "ACTION TAKEN", "isControlRequired": true, - "isUnitAvailable": true, + "hasNoUnitAvailable": true, "createdAt": "2023-09-25T15:17:32.847553Z", "validityTime": 1, "isArchived": true, diff --git a/frontend/src/features/missions/Overlays/ReportingToAttach/index.tsx b/frontend/src/features/missions/Overlays/ReportingToAttach/index.tsx new file mode 100644 index 000000000..90d6f2e6a --- /dev/null +++ b/frontend/src/features/missions/Overlays/ReportingToAttach/index.tsx @@ -0,0 +1,44 @@ +import { useState } from 'react' + +import { Layers } from '../../../../domain/entities/layers/constants' +import { useAppSelector } from '../../../../hooks/useAppSelector' +import { OverlayPositionOnCentroid } from '../../../map/overlays/OverlayPositionOnCentroid' +import { ReportingCard } from '../../../map/overlays/reportings/ReportingCard' + +import type { BaseMapChildrenProps } from '../../../map/BaseMap' + +const MARGINS = { + xLeft: 50, + xMiddle: 30, + xRight: -55, + yBottom: 50, + yMiddle: 50, + yTop: -55 +} + +export function ReportingToAttachOverlays({ currentFeatureOver, map }: BaseMapChildrenProps) { + const { displayReportingToAttachLayer } = useAppSelector(state => state.global) + + const [hoveredMargins, setHoveredMargins] = useState(MARGINS) + + const currentfeatureId = currentFeatureOver?.getId() + const displayHoveredFeature = + typeof currentfeatureId === 'string' && currentfeatureId.startsWith(Layers.REPORTING_TO_ATTACH_ON_MISSION.code) + + const updateHoveredMargins = (cardHeight: number) => { + if (MARGINS.yTop - cardHeight !== hoveredMargins.yTop) { + setHoveredMargins({ ...hoveredMargins, yTop: MARGINS.yTop - cardHeight }) + } + } + + return ( + + + + ) +} diff --git a/frontend/src/store/index.ts b/frontend/src/store/index.ts index 910ac49ac..618bf44bd 100644 --- a/frontend/src/store/index.ts +++ b/frontend/src/store/index.ts @@ -2,8 +2,8 @@ import { type AnyAction, type ThunkAction, configureStore, isPlain } from '@redu import { setupListeners } from '@reduxjs/toolkit/query' import { FLUSH, PAUSE, PERSIST, PURGE, REGISTER, REHYDRATE } from 'redux-persist' +import { homeMiddlewares, homeReducers } from './reducers' import { monitorenvPrivateApi, monitorenvPublicApi } from '../api/api' -import { homeReducers, homeMiddlewares } from '../domain/shared_slices' import { regulatoryActionSanitizer } from '../domain/shared_slices/Regulatory' const homeStore = configureStore({ diff --git a/frontend/src/store/reducers.ts b/frontend/src/store/reducers.ts new file mode 100644 index 000000000..26d465524 --- /dev/null +++ b/frontend/src/store/reducers.ts @@ -0,0 +1,87 @@ +// TODO We should move that into `/frontend/src/store` directory. + +import { combineReducers } from '@reduxjs/toolkit' + +import { ampsAPI, ampsErrorLoggerMiddleware } from '../api/ampsAPI' +import { monitorenvPrivateApi, monitorenvPublicApi } from '../api/api' +import { controlThemesAPI } from '../api/controlThemesAPI' +import { infractionsAPI } from '../api/infractionsAPI' +import { legacyControlUnitsAPI } from '../api/legacyControlUnitsAPI' +import { regulatoryLayersAPI } from '../api/regulatoryLayersAPI' +import { semaphoresAPI } from '../api/semaphoresAPI' +import { administrativeSlicePersistedReducer } from '../domain/shared_slices/Administrative' +import { drawReducer } from '../domain/shared_slices/Draw' +import { globalReducer } from '../domain/shared_slices/Global' +import { interestPointSlicePersistedReducer } from '../domain/shared_slices/InterestPoint' +import { layerSidebarSlice } from '../domain/shared_slices/LayerSidebar' +import { mapSliceReducer } from '../domain/shared_slices/Map' +import { measurementSlicePersistedReducer } from '../domain/shared_slices/Measurement' +import { missionFiltersPersistedReducer } from '../domain/shared_slices/MissionFilters' +import { missionStateSliceReducer } from '../domain/shared_slices/MissionsState' +import { multiMissionsSliceReducer } from '../domain/shared_slices/MultiMissions' +import { regulatorySlicePersistedReducer } from '../domain/shared_slices/Regulatory' +import { regulatoryMetadataSliceReducer } from '../domain/shared_slices/RegulatoryMetadata' +import { reportingSliceReducer } from '../domain/shared_slices/reporting' +import { reportingFiltersPersistedReducer } from '../domain/shared_slices/ReportingsFilters' +import { selectedAmpSlicePersistedReducer } from '../domain/shared_slices/SelectedAmp' +import { semaphoresPersistedReducer } from '../domain/shared_slices/SemaphoresSlice' +import { administrationTablePersistedReducer } from '../features/Administration/components/AdministrationTable/slice' +import { backOfficeReducer } from '../features/BackOffice/slice' +import { baseTablePersistedReducer } from '../features/Base/components/BaseTable/slice' +import { controlUnitDialogReducer } from '../features/ControlUnit/components/ControlUnitDialog/slice' +import { controlUnitListDialogPersistedReducer } from '../features/ControlUnit/components/ControlUnitListDialog/slice' +import { controlUnitTablePersistedReducer } from '../features/ControlUnit/components/ControlUnitTable/slice' +import { layerSearchSliceReducer } from '../features/layersSelector/search/slice' +import { mainWindowReducer } from '../features/MainWindow/slice' +import { attachReportingToMissionsSliceReducer } from '../features/missions/MissionForm/AttachReporting/slice' +import { attachMissionToReportingSliceReducer } from '../features/Reportings/ReportingForm/AttachMission/slice' +import { sideWindowReducer } from '../features/SideWindow/slice' + +// TODO Maybe add a specifc store for the backoffice? +// But it won't be necessarily cleaner since current APIs are also needed in the home anyway. +export const homeReducers = combineReducers({ + [monitorenvPrivateApi.reducerPath]: monitorenvPrivateApi.reducer, + [monitorenvPublicApi.reducerPath]: monitorenvPublicApi.reducer, + administrative: administrativeSlicePersistedReducer, + attachMissionToReporting: attachMissionToReportingSliceReducer, + attachReportingToMission: attachReportingToMissionsSliceReducer, + backOffice: backOfficeReducer, + backOfficeAdministrationList: administrationTablePersistedReducer, + backOfficeBaseList: baseTablePersistedReducer, + backOfficeControlUnitList: controlUnitTablePersistedReducer, + draw: drawReducer, + global: globalReducer, + interestPoint: interestPointSlicePersistedReducer, + layerSearch: layerSearchSliceReducer, + mainWindow: mainWindowReducer, + map: mapSliceReducer, + mapControlUnitDialog: controlUnitDialogReducer, + mapControlUnitListDialog: controlUnitListDialogPersistedReducer, + measurement: measurementSlicePersistedReducer, + missionFilters: missionFiltersPersistedReducer, + missionState: missionStateSliceReducer, + multiMissions: multiMissionsSliceReducer, + regulatory: regulatorySlicePersistedReducer, + regulatoryMetadata: regulatoryMetadataSliceReducer, + [layerSidebarSlice.name]: layerSidebarSlice.reducer, + [ampsAPI.reducerPath]: ampsAPI.reducer, + [regulatoryLayersAPI.reducerPath]: regulatoryLayersAPI.reducer, + [controlThemesAPI.reducerPath]: controlThemesAPI.reducer, + [infractionsAPI.reducerPath]: infractionsAPI.reducer, + [semaphoresAPI.reducerPath]: semaphoresAPI.reducer, + reporting: reportingSliceReducer, + reportingFilters: reportingFiltersPersistedReducer, + selectedAmp: selectedAmpSlicePersistedReducer, + semaphoresSlice: semaphoresPersistedReducer, + sideWindow: sideWindowReducer +}) + +export const homeMiddlewares = [ + ampsAPI.middleware, + ampsErrorLoggerMiddleware, + regulatoryLayersAPI.middleware, + controlThemesAPI.middleware, + legacyControlUnitsAPI.middleware, + infractionsAPI.middleware, + semaphoresAPI.middleware +] diff --git a/frontend/store/index.tsx b/frontend/store/index.tsx deleted file mode 100644 index bf65a7f8d..000000000 --- a/frontend/store/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { configureStore, isPlain } from '@reduxjs/toolkit' -import { setupListeners } from '@reduxjs/toolkit/query' -import { FLUSH, PAUSE, PERSIST, PURGE, REGISTER, REHYDRATE } from 'redux-persist' - -import { homeMiddlewares, homeReducers } from '../src/domain/shared_slices' -import { regulatoryActionSanitizer } from '../src/domain/shared_slices/Regulatory' - -const homeStore = configureStore({ - devTools: { - actionSanitizer: regulatoryActionSanitizer - }, - middleware: getDefaultMiddleware => - getDefaultMiddleware({ - immutableCheck: { - ignoredPaths: ['regulatory', 'layerSearch'] - }, - // TODO Create a Redux middleware to properly serialize/deserialize `Date`, `Error` objects into plain objects. - // https://redux-toolkit.js.org/api/serializabilityMiddleware - serializableCheck: { - ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER, 'regulatory/setRegulatoryLayers'], - ignoredPaths: ['regulatory', 'layerSearch'], - isSerializable: (value: any) => isPlain(value) || value instanceof Date || value instanceof Error - } - }).concat(homeMiddlewares), - reducer: homeReducers -}) - -setupListeners(homeStore.dispatch) - -export { homeStore } - -// https://react-redux.js.org/using-react-redux/usage-with-typescript#define-root-state-and-dispatch-types -// Infer the `RootState` and `AppDispatch` types from the store itself -export type HomeRootState = ReturnType -// Inferred type: { global: GlobalState, ... } -export type AppDispatch = typeof homeStore.dispatch -export type AppGetState = typeof homeStore.getState diff --git a/frontend/store/reducers.ts b/frontend/store/reducers.ts deleted file mode 100644 index 8efb21428..000000000 --- a/frontend/store/reducers.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { combineReducers } from '@reduxjs/toolkit' - -import { ampsAPI, ampsErrorLoggerMiddleware } from '../src/api/ampsAPI' -import { controlThemesAPI } from '../src/api/controlThemesAPI' -import { controlUnitsAPI } from '../src/api/controlUnitsAPI' -import { infractionsAPI } from '../src/api/infractionsAPI' -import { missionsAPI } from '../src/api/missionsAPI' -import { regulatoryLayersAPI } from '../src/api/regulatoryLayersAPI' -import { reportingsAPI } from '../src/api/reportingsAPI' -import { semaphoresAPI } from '../src/api/semaphoresAPI' -import { administrativeSlicePersistedReducer } from '../src/domain/shared_slices/Administrative' -import { drawReducer } from '../src/domain/shared_slices/Draw' -import { globalReducer } from '../src/domain/shared_slices/Global' -import { interestPointSlicePersistedReducer } from '../src/domain/shared_slices/InterestPoint' -import { layerSidebarSlice } from '../src/domain/shared_slices/LayerSidebar' -import { mapSliceReducer } from '../src/domain/shared_slices/Map' -import { measurementSlicePersistedReducer } from '../src/domain/shared_slices/Measurement' -import { missionFiltersPersistedReducer } from '../src/domain/shared_slices/MissionFilters' -import { missionStateSliceReducer } from '../src/domain/shared_slices/MissionsState' -import { multiMissionsSliceReducer } from '../src/domain/shared_slices/MultiMissions' -import { regulatorySlicePersistedReducer } from '../src/domain/shared_slices/Regulatory' -import { regulatoryMetadataSliceReducer } from '../src/domain/shared_slices/RegulatoryMetadata' -import { reportingSliceReducer } from '../src/domain/shared_slices/reporting' -import { reportingFiltersPersistedReducer } from '../src/domain/shared_slices/ReportingsFilters' -import { selectedAmpSlicePersistedReducer } from '../src/domain/shared_slices/SelectedAmp' -import { semaphoresPersistedReducer } from '../src/domain/shared_slices/SemaphoresSlice' -import { layerSearchSliceReducer } from '../src/features/layersSelector/search/LayerSearch.slice' -import { sideWindowReducer } from '../src/features/SideWindow/slice' - -export const homeReducers = combineReducers({ - administrative: administrativeSlicePersistedReducer, - draw: drawReducer, - global: globalReducer, - interestPoint: interestPointSlicePersistedReducer, - layerSearch: layerSearchSliceReducer, - map: mapSliceReducer, - measurement: measurementSlicePersistedReducer, - missionFilters: missionFiltersPersistedReducer, - missionState: missionStateSliceReducer, - multiMissions: multiMissionsSliceReducer, - regulatory: regulatorySlicePersistedReducer, - regulatoryMetadata: regulatoryMetadataSliceReducer, - reporting: reportingSliceReducer, - [layerSidebarSlice.name]: layerSidebarSlice.reducer, - [ampsAPI.reducerPath]: ampsAPI.reducer, - [regulatoryLayersAPI.reducerPath]: regulatoryLayersAPI.reducer, - [missionsAPI.reducerPath]: missionsAPI.reducer, - [controlThemesAPI.reducerPath]: controlThemesAPI.reducer, - [controlUnitsAPI.reducerPath]: controlUnitsAPI.reducer, - [infractionsAPI.reducerPath]: infractionsAPI.reducer, - [semaphoresAPI.reducerPath]: semaphoresAPI.reducer, - reportingFilters: reportingFiltersPersistedReducer, - [reportingsAPI.reducerPath]: reportingsAPI.reducer, - selectedAmp: selectedAmpSlicePersistedReducer, - semaphoresSlice: semaphoresPersistedReducer, - sideWindow: sideWindowReducer -}) - -export const homeMiddlewares = [ - ampsAPI.middleware, - ampsErrorLoggerMiddleware, - missionsAPI.middleware, - regulatoryLayersAPI.middleware, - controlThemesAPI.middleware, - controlUnitsAPI.middleware, - infractionsAPI.middleware, - semaphoresAPI.middleware, - reportingsAPI.middleware -]