Skip to content

Commit

Permalink
Préavis - Un préavis envoyé reste "En cours de diffusion" (#3693)
Browse files Browse the repository at this point in the history
## Linked issues

- Resolve #3689

----

- [ ] Tests E2E (Cypress)
  • Loading branch information
louptheron authored Sep 30, 2024
2 parents ab81808 + 27a3c54 commit 88a435f
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 26 deletions.
1 change: 0 additions & 1 deletion frontend/src/api/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export enum HttpStatusCode {
}

export enum RtkCacheTagType {
PriorNotification = 'PriorNotification',
PriorNotificationDocuments = 'PriorNotificationDocuments',
PriorNotificationTypes = 'PriorNotificationTypes',
PriorNotifications = 'PriorNotifications',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { useInterval } from '@features/PriorNotification/hooks/useInterval'
import { PriorNotification } from '@features/PriorNotification/PriorNotification.types'
import { refreshPriorNotification } from '@features/PriorNotification/useCases/refreshPriorNotification'
import { verifyAndSendPriorNotification } from '@features/PriorNotification/useCases/verifyAndSendPriorNotification'
import { getPriorNotificationIdentifier } from '@features/PriorNotification/utils'
import { useMainAppDispatch } from '@hooks/useMainAppDispatch'
Expand All @@ -24,6 +27,26 @@ export function LogbookPriorNotificationForm() {
state => state.priorNotification.openedPriorNotificationDetail
)

const isBeingSent =
openedPriorNotificationDetail?.state === PriorNotification.State.PENDING_SEND ||
openedPriorNotificationDetail?.state === PriorNotification.State.PENDING_AUTO_SEND

useInterval(
() => {
assertNotNullish(openedPriorNotificationDetail)

dispatch(
refreshPriorNotification(
getPriorNotificationIdentifier(openedPriorNotificationDetail),
openedPriorNotificationDetail.fingerprint,
openedPriorNotificationDetail.isManuallyCreated
)
)
},
isBeingSent,
5000
)

const displayedErrorKey = displayedError ? DisplayedErrorKey.SIDE_WINDOW_PRIOR_NOTIFICATION_FORM_ERROR : undefined

const verifyAndSend = async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ErrorWall } from '@components/ErrorWall'
import { useInterval } from '@features/PriorNotification/hooks/useInterval'
import { refreshPriorNotification } from '@features/PriorNotification/useCases/refreshPriorNotification'
import { verifyAndSendPriorNotification } from '@features/PriorNotification/useCases/verifyAndSendPriorNotification'
import { getPriorNotificationIdentifier } from '@features/PriorNotification/utils'
import { useMainAppDispatch } from '@hooks/useMainAppDispatch'
Expand All @@ -14,11 +16,11 @@ import { LoadingSpinnerWall } from 'ui/LoadingSpinnerWall'
import { FORM_VALIDATION_SCHEMA } from './constants'
import { Content } from './Content'
import { SideWindowCard } from '../../../../components/SideWindowCard'
import { PriorNotification } from '../../PriorNotification.types'
import { priorNotificationActions } from '../../slice'
import { createOrUpdateManualPriorNotification } from '../../useCases/createOrUpdateManualPriorNotification'

import type { ManualPriorNotificationFormValues } from './types'
import type { PriorNotification } from '../../PriorNotification.types'

export function ManualPriorNotificationForm() {
const dispatch = useMainAppDispatch()
Expand All @@ -33,6 +35,26 @@ export function ManualPriorNotificationForm() {
state => state.priorNotification.openedPriorNotificationDetail
)

const isBeingSent =
openedPriorNotificationDetail?.state === PriorNotification.State.PENDING_SEND ||
openedPriorNotificationDetail?.state === PriorNotification.State.PENDING_AUTO_SEND

useInterval(
() => {
assertNotNullish(openedPriorNotificationDetail)

dispatch(
refreshPriorNotification(
getPriorNotificationIdentifier(openedPriorNotificationDetail),
openedPriorNotificationDetail.fingerprint,
openedPriorNotificationDetail.isManuallyCreated
)
)
},
isBeingSent,
5000
)

const [shouldValidateOnChange, setShouldValidateOnChange] = useState(false)
const [isLoading, setIsLoading] = useState(false)

Expand Down
26 changes: 26 additions & 0 deletions frontend/src/features/PriorNotification/hooks/useInterval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useEffect, useRef } from 'react'

export function useInterval(callback: () => void, condition: boolean, delay: number): void {
const savedCallback = useRef<() => void>()
const intervalId = useRef<number | undefined>()

useEffect(() => {
savedCallback.current = callback
}, [callback])

useEffect(() => {
if (!condition) {
return () => clearInterval(intervalId.current)
}

function tick() {
if (savedCallback.current) {
savedCallback.current()
}
}

intervalId.current = window.setInterval(tick, delay)

return () => clearInterval(intervalId.current)
}, [condition, delay])
}
22 changes: 5 additions & 17 deletions frontend/src/features/PriorNotification/priorNotificationApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const priorNotificationApi = monitorfishApi.injectEndpoints({
isManuallyCreated: boolean
}
>({
providesTags: (_, __, { reportId }) => [{ id: reportId, type: RtkCacheTagType.PriorNotification }],
forceRefetch: () => true,
query: ({ isManuallyCreated, operationDate, reportId }) =>
getUrlOrPathWithQueryParams(`/prior_notifications/${reportId}`, { isManuallyCreated, operationDate }),
transformErrorResponse: response => new FrontendApiError(GET_PRIOR_NOTIFICATION_DETAIL_ERROR_MESSAGE, response)
Expand Down Expand Up @@ -152,10 +152,7 @@ export const priorNotificationApi = monitorfishApi.injectEndpoints({
isManuallyCreated: boolean
}
>({
invalidatesTags: (_, __, { reportId }) => [
{ type: RtkCacheTagType.PriorNotifications },
{ id: reportId, type: RtkCacheTagType.PriorNotification }
],
invalidatesTags: () => [{ type: RtkCacheTagType.PriorNotifications }],
query: ({ isManuallyCreated, operationDate, reportId }) => ({
method: 'PUT',
url: getUrlOrPathWithQueryParams(`/prior_notifications/${reportId}/invalidate`, {
Expand All @@ -174,10 +171,7 @@ export const priorNotificationApi = monitorfishApi.injectEndpoints({
reportId: string
}
>({
invalidatesTags: (_, __, { reportId }) => [
{ type: RtkCacheTagType.PriorNotifications },
{ id: reportId, type: RtkCacheTagType.PriorNotification }
],
invalidatesTags: () => [{ type: RtkCacheTagType.PriorNotifications }],
query: ({ data, operationDate, reportId }) => ({
body: data,
method: 'PUT',
Expand All @@ -193,10 +187,7 @@ export const priorNotificationApi = monitorfishApi.injectEndpoints({
reportId: string
}
>({
invalidatesTags: (_, __, { reportId }) => [
{ type: RtkCacheTagType.PriorNotifications },
{ id: reportId, type: RtkCacheTagType.PriorNotification }
],
invalidatesTags: () => [{ type: RtkCacheTagType.PriorNotifications }],
query: ({ data, reportId }) => ({
body: data,
method: 'PUT',
Expand All @@ -211,10 +202,7 @@ export const priorNotificationApi = monitorfishApi.injectEndpoints({
isManuallyCreated: boolean
}
>({
invalidatesTags: (_, __, { reportId }) => [
{ type: RtkCacheTagType.PriorNotifications },
{ id: reportId, type: RtkCacheTagType.PriorNotification }
],
invalidatesTags: () => [{ type: RtkCacheTagType.PriorNotifications }],
query: ({ isManuallyCreated, operationDate, reportId }) => ({
method: 'POST',
url: getUrlOrPathWithQueryParams(`/prior_notifications/${reportId}/verify_and_send`, {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RtkCacheTagType } from '@api/constants'
import { addMainWindowBanner } from '@features/SideWindow/useCases/addMainWindowBanner'
import { addSideWindowBanner } from '@features/SideWindow/useCases/addSideWindowBanner'
import { customSentry, CustomSentryMeasurementName } from '@libs/customSentry'
import { DisplayedErrorKey } from '@libs/DisplayedError/constants'
import { FrontendApiError } from '@libs/FrontendApiError'
Expand Down Expand Up @@ -54,7 +54,7 @@ export const openLogbookPriorNotificationForm =
if (logbookPriorNotification.logbookMessage.isDeleted) {
dispatch(priorNotificationActions.closePriorNotificationCardAndForm())
dispatch(
addMainWindowBanner({
addSideWindowBanner({
children: 'Ce préavis a été supprimé (entre temps).',
closingDelay: 5000,
isClosable: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RtkCacheTagType } from '@api/constants'
import { addMainWindowBanner } from '@features/SideWindow/useCases/addMainWindowBanner'
import { addSideWindowBanner } from '@features/SideWindow/useCases/addSideWindowBanner'
import { DisplayedErrorKey } from '@libs/DisplayedError/constants'
import { FrontendApiError } from '@libs/FrontendApiError'
import { Level } from '@mtes-mct/monitor-ui'
Expand Down Expand Up @@ -43,7 +43,7 @@ export const openPriorNotificationCard =
if (priorNotificationDetail.logbookMessage.isDeleted) {
dispatch(priorNotificationActions.closePriorNotificationCardAndForm())
dispatch(
addMainWindowBanner({
addSideWindowBanner({
children: 'Ce préavis a été supprimé (entre temps).',
closingDelay: 5000,
isClosable: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { RtkCacheTagType } from '@api/constants'
import { addSideWindowBanner } from '@features/SideWindow/useCases/addSideWindowBanner'
import { DisplayedErrorKey } from '@libs/DisplayedError/constants'
import { FrontendApiError } from '@libs/FrontendApiError'
import { Level } from '@mtes-mct/monitor-ui'
import { handleThunkError } from '@utils/handleThunkError'
import { displayOrLogError } from 'domain/use_cases/error/displayOrLogError'

import { priorNotificationApi } from '../priorNotificationApi'
import { priorNotificationActions } from '../slice'

import type { PriorNotification } from '../PriorNotification.types'
import type { MainAppThunk } from '@store'

export const refreshPriorNotification =
(
identifier: PriorNotification.Identifier,
fingerprint: string,
isManuallyCreated: boolean
): MainAppThunk<Promise<void>> =>
async dispatch => {
try {
const logbookPriorNotification = await dispatch(
priorNotificationApi.endpoints.getPriorNotificationDetail.initiate({
...identifier,
isManuallyCreated
})
).unwrap()

// Update prior notification list if prior notification fingerprint has changed
if (logbookPriorNotification.fingerprint !== fingerprint) {
dispatch(priorNotificationApi.util.invalidateTags([RtkCacheTagType.PriorNotifications]))
}

// Close card and display a warning banner if prior notification has been deleted (in the meantime)
if (logbookPriorNotification.logbookMessage.isDeleted) {
dispatch(priorNotificationActions.closePriorNotificationCardAndForm())
dispatch(
addSideWindowBanner({
children: 'Ce préavis a été supprimé (entre temps).',
closingDelay: 5000,
isClosable: true,
level: Level.WARNING,
withAutomaticClosing: true
})
)

return
}

dispatch(priorNotificationActions.setOpenedPriorNotificationDetail(logbookPriorNotification))
} catch (err) {
if (err instanceof FrontendApiError) {
dispatch(
displayOrLogError(
err,
() => refreshPriorNotification(identifier, fingerprint, isManuallyCreated),
true,
DisplayedErrorKey.SIDE_WINDOW_PRIOR_NOTIFICATION_FORM_ERROR
)
)

return
}

handleThunkError(err)
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { bannerStackAdapter, sideWindowActions } from '../slice'

import type { SideWindow } from '../SideWindow.types'
import type { MainAppThunk } from '@store/index'
import type { MainAppThunk } from '@store'

/**
* Add a banner to the main window.
* Add a banner to the side window.
*
* @param props Component props of the `<Banner />` to add.
* @returns ID of the added banner (used to remove it if needed).
*/
export const addMainWindowBanner =
export const addSideWindowBanner =
(props: SideWindow.BannerStackItemProps): MainAppThunk<number> =>
(dispatch, getState) => {
const { bannerStack } = getState().sideWindow
Expand Down

0 comments on commit 88a435f

Please sign in to comment.