diff --git a/app/javascript/flavours/glitch/store/middlewares/errors.ts b/app/javascript/flavours/glitch/store/middlewares/errors.ts index e11aa78178..977a09a464 100644 --- a/app/javascript/flavours/glitch/store/middlewares/errors.ts +++ b/app/javascript/flavours/glitch/store/middlewares/errors.ts @@ -1,16 +1,27 @@ -import { isAction } from '@reduxjs/toolkit'; +import { + isAction, + isAsyncThunkAction, + isRejectedWithValue, +} from '@reduxjs/toolkit'; import type { Action, Middleware } from '@reduxjs/toolkit'; import type { RootState } from '..'; import { showAlertForError } from '../../actions/alerts'; +import type { AsyncThunkRejectValue } from '../typed_functions'; const defaultFailSuffix = 'FAIL'; const isFailedAction = new RegExp(`${defaultFailSuffix}$`, 'g'); -interface ActionWithMaybeAlertParams extends Action { - skipAlert?: boolean; - skipNotFound?: boolean; - error?: unknown; +interface ActionWithMaybeAlertParams extends Action, AsyncThunkRejectValue {} + +interface RejectedAction extends Action { + payload: AsyncThunkRejectValue; +} + +function isRejectedActionWithPayload( + action: unknown, +): action is RejectedAction { + return isAsyncThunkAction(action) && isRejectedWithValue(action); } function isActionWithmaybeAlertParams( @@ -23,7 +34,11 @@ export const errorsMiddleware: Middleware, RootState> = ({ dispatch }) => (next) => (action) => { - if ( + if (isRejectedActionWithPayload(action) && !action.payload.skipAlert) { + dispatch( + showAlertForError(action.payload.error, action.payload.skipNotFound), + ); + } else if ( isActionWithmaybeAlertParams(action) && !action.skipAlert && action.type.match(isFailedAction) diff --git a/app/javascript/flavours/glitch/store/typed_functions.ts b/app/javascript/flavours/glitch/store/typed_functions.ts index 4859b82651..b66d7545c5 100644 --- a/app/javascript/flavours/glitch/store/typed_functions.ts +++ b/app/javascript/flavours/glitch/store/typed_functions.ts @@ -7,8 +7,14 @@ import type { AppDispatch, RootState } from './store'; export const useAppDispatch = useDispatch.withTypes(); export const useAppSelector = useSelector.withTypes(); +export interface AsyncThunkRejectValue { + skipAlert?: boolean; + skipNotFound?: boolean; + error?: unknown; +} + export const createAppAsyncThunk = createAsyncThunk.withTypes<{ state: RootState; dispatch: AppDispatch; - rejectValue: string; + rejectValue: AsyncThunkRejectValue; }>();