diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 1eeb8a586a..cd2da11013 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -49,6 +49,7 @@
"react-select": "5.8.3",
"react-toastify": "9.1.3",
"redux": "5.0.1",
+ "redux-mock-store": "1.5.5",
"redux-persist": "6.0.0",
"redux-thunk": "3.1.0",
"rsuite": "5.54.0",
@@ -13173,6 +13174,11 @@
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
"license": "MIT"
},
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
+ },
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -16285,6 +16291,17 @@
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
"license": "MIT"
},
+ "node_modules/redux-mock-store": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/redux-mock-store/-/redux-mock-store-1.5.5.tgz",
+ "integrity": "sha512-YxX+ofKUTQkZE4HbhYG4kKGr7oCTJfB0GLy7bSeqx86GLpGirrbUWstMnqXkqHNaQpcnbMGbof2dYs5KsPE6Zg==",
+ "dependencies": {
+ "lodash.isplainobject": "^4.0.6"
+ },
+ "peerDependencies": {
+ "redux": "*"
+ }
+ },
"node_modules/redux-persist": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 614cad8477..e53b097bb2 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -74,6 +74,7 @@
"react-select": "5.8.3",
"react-toastify": "9.1.3",
"redux": "5.0.1",
+ "redux-mock-store": "1.5.5",
"redux-persist": "6.0.0",
"redux-thunk": "3.1.0",
"rsuite": "5.54.0",
@@ -138,9 +139,9 @@
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"lint-staged": "14.0.1",
+ "madge": "8.0.0",
"ora": "8.1.1",
"postgres": "3.4.5",
- "madge": "8.0.0",
"prettier": "3.4.1",
"puppeteer": "22.15.0",
"strip-json-comments": "5.0.1",
diff --git a/frontend/src/features/Reporting/components/ReportingCard/__tests__/ReportingCard.test.tsx b/frontend/src/features/Reporting/components/ReportingCard/__tests__/ReportingCard.test.tsx
index 4a395eab5f..faebf959ba 100644
--- a/frontend/src/features/Reporting/components/ReportingCard/__tests__/ReportingCard.test.tsx
+++ b/frontend/src/features/Reporting/components/ReportingCard/__tests__/ReportingCard.test.tsx
@@ -1,31 +1,34 @@
import { Seafront } from '@constants/seafront'
+import { PendingAlertValueType } from '@features/Alert/types'
import { ReportingCard } from '@features/Reporting/components/ReportingCard'
import { ReportingType } from '@features/Reporting/types'
-import { afterAll, describe, expect, it } from '@jest/globals'
+import { afterAll, describe, expect, it, jest } from '@jest/globals'
import { THEME, ThemeProvider } from '@mtes-mct/monitor-ui'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { noop } from 'lodash'
+import { Provider } from 'react-redux'
+import configureStore from 'redux-mock-store'
import { VesselIdentifier } from '../../../../../domain/entities/vessel/types'
-import { PendingAlertValueType } from '../../../../Alert/types'
import type { PendingAlertReporting } from '@features/Reporting/types'
-// @ts-ignore
-jest.mock('../../../useCases/archiveReporting', () => () => ({ archiveReporting: jest.fn() }))
-// @ts-ignore
+jest.mock('../../../useCases/archiveReporting', () => ({ archiveReporting: jest.fn() }))
jest.mock('../../../../../hooks/useMainAppDispatch', () => ({ useMainAppDispatch: () => {} }))
+jest.mock('../../../useCases/deleteReporting', () => ({ deleteReporting: jest.fn() }))
describe('ReportingCard()', () => {
afterAll(() => {
// Reset module registry to clear the mock
- // @ts-ignore
jest.resetModules()
})
it('should display all other dates', async () => {
// Given
+ const mockStore = configureStore()
+ const store = mockStore({})
+
const reporting: PendingAlertReporting = {
creationDate: '2023-10-30T09:10:00Z',
externalReferenceNumber: '',
@@ -57,17 +60,19 @@ describe('ReportingCard()', () => {
}
render(
-
-
-
+
+
+
+
+
)
const linkElement = screen.getByText(/Voir les dates des autres alertes/i)
diff --git a/frontend/src/features/Reporting/components/ReportingCard/index.tsx b/frontend/src/features/Reporting/components/ReportingCard/index.tsx
index fa211d93c5..fa01ae574e 100644
--- a/frontend/src/features/Reporting/components/ReportingCard/index.tsx
+++ b/frontend/src/features/Reporting/components/ReportingCard/index.tsx
@@ -1,5 +1,6 @@
import { ConfirmationModal } from '@components/ConfirmationModal'
import { getAlertNameFromType } from '@features/Alert/components/SideWindowAlerts/AlertListAndReportingList/utils'
+import { PendingAlertValueType } from '@features/Alert/types'
import { deleteReporting } from '@features/Reporting/useCases/deleteReporting'
import { reportingIsAnInfractionSuspicion } from '@features/Reporting/utils'
import { useMainAppDispatch } from '@hooks/useMainAppDispatch'
@@ -35,6 +36,9 @@ export function ReportingCard({
const reportingName = Object.values(ReportingTypeCharacteristics).find(
reportingType => reportingType.code === reporting.type
)?.name
+ const canBeArchived = !(
+ reporting.type === ReportingType.ALERT && reporting.value.type === PendingAlertValueType.MISSING_FAR_48_HOURS_ALERT
+ )
const alertDateTime = getDateTime(
reporting.type === ReportingType.ALERT ? reporting.validationDate : reporting.creationDate,
true
@@ -54,7 +58,7 @@ export function ReportingCard({
}, [reporting, reportingName])
const archive = () => {
- dispatch(archiveReporting(reporting.id, reporting.type))
+ dispatch(archiveReporting(reporting))
}
const askForDeletionConfirmation = () => {
@@ -166,7 +170,11 @@ export function ReportingCard({
Icon={Icon.Archive}
iconSize={20}
onClick={archive}
- title="Archiver ce signalement"
+ title={
+ canBeArchived
+ ? 'Archiver ce signalement'
+ : `Ce signalement sera archivé sous la forme de 2 alertes "Absence de message FAR en 24h"`
+ }
/>
jest.fn())
+// @ts-ignore
+jest.mock('../deleteReporting', () => ({
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ __esModule: true,
+ // @ts-ignore
+ deleteReporting: jest.fn()
+}))
+
+describe('archiveReporting()', () => {
+ const INITIAL_STATE = {
+ vessel: {
+ selectedVesselIdentity: {
+ externalReferenceNumber: '',
+ flagState: '',
+ internalReferenceNumber: '',
+ vesselId: 1234568,
+ vesselIdentifier: VesselIdentifier.INTERNAL_REFERENCE_NUMBER,
+ vesselName: ''
+ }
+ }
+ }
+
+ afterAll(() => {
+ // Reset module registry to clear the mock
+ // @ts-ignore
+ jest.resetModules()
+ })
+
+ it('Should delete reporting When alert is MISSING_FAR_48_HOURS_ALERT', async () => {
+ // When
+ mockedDispatch(archiveReporting(fortyHeightHourAlertReporting), INITIAL_STATE)
+
+ // Then
+ expect(deleteReporting).toHaveBeenCalled()
+ })
+
+ it('Should not delete reporting When the alert is not an MISSING_FAR_48_HOURS_ALERT', async () => {
+ // Given
+ const otherAlertReporting = {
+ ...fortyHeightHourAlertReporting,
+ value: {
+ ...fortyHeightHourAlertReporting.value,
+ type: PendingAlertValueType.MISSING_FAR_ALERT
+ }
+ }
+
+ // When
+ mockedDispatch(archiveReporting(otherAlertReporting), INITIAL_STATE)
+
+ // Then
+ expect(deleteReporting).toHaveBeenCalledTimes(0)
+ })
+})
diff --git a/frontend/src/features/Reporting/useCases/archiveReporting.ts b/frontend/src/features/Reporting/useCases/archiveReporting.ts
index 8968f2df71..3bdf246029 100644
--- a/frontend/src/features/Reporting/useCases/archiveReporting.ts
+++ b/frontend/src/features/Reporting/useCases/archiveReporting.ts
@@ -1,3 +1,6 @@
+import { PendingAlertValueType } from '@features/Alert/types'
+import { ReportingType } from '@features/Reporting/types'
+import { deleteReporting } from '@features/Reporting/useCases/deleteReporting'
import { renderVesselFeatures } from '@features/Vessel/useCases/renderVesselFeatures'
import { DisplayedErrorKey } from '@libs/DisplayedError/constants'
@@ -6,20 +9,29 @@ import { displayOrLogError } from '../../../domain/use_cases/error/displayOrLogE
import { removeVesselReporting } from '../../Vessel/slice'
import { reportingApi } from '../reportingApi'
-import type { ReportingType } from '@features/Reporting/types'
+import type { Reporting } from '@features/Reporting/types'
import type { MainAppThunk } from '@store'
export const archiveReporting =
- (id: number, type: ReportingType): MainAppThunk> =>
+ (reporting: Reporting.Reporting): MainAppThunk> =>
async (dispatch, getState) => {
const { selectedVesselIdentity } = getState().vessel
try {
- await dispatch(reportingApi.endpoints.archiveReporting.initiate(id)).unwrap()
+ if (
+ reporting.type === ReportingType.ALERT &&
+ reporting.value.type === PendingAlertValueType.MISSING_FAR_48_HOURS_ALERT
+ ) {
+ await dispatch(deleteReporting(reporting.id, reporting.type))
+
+ return
+ }
+
+ await dispatch(reportingApi.endpoints.archiveReporting.initiate(reporting.id)).unwrap()
dispatch(
removeVesselReporting({
- reportingType: type,
+ reportingType: reporting.type,
vesselFeatureId: Vessel.getVesselFeatureId(selectedVesselIdentity)
})
)
@@ -29,7 +41,7 @@ export const archiveReporting =
dispatch(
displayOrLogError(
error as Error,
- () => archiveReporting(id, type),
+ () => archiveReporting(reporting),
true,
DisplayedErrorKey.VESSEL_SIDEBAR_ERROR
)
diff --git a/frontend/src/store/__tests__/utils.ts b/frontend/src/store/__tests__/utils.ts
new file mode 100644
index 0000000000..785c7455db
--- /dev/null
+++ b/frontend/src/store/__tests__/utils.ts
@@ -0,0 +1,22 @@
+import { jest } from '@jest/globals'
+
+/**
+ * To be used to capture all dispatched actions.
+ *
+ * we could have more middleware functions being called within the
+ * use-case middleware, and we should be able to capture all of these events.
+ */
+export const mockedDispatch = (action, initialState) => {
+ const store = {
+ dispatch: jest.fn(fn => {
+ if (typeof fn === 'function') {
+ fn(store.dispatch, store.getState)
+ }
+ }),
+ getState: jest.fn(() => initialState)
+ }
+
+ action(store.dispatch, store.getState)
+
+ return store
+}