From d3f51ec88fa5f040b0d7390b3fbd20fefb411670 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <p.gawron@atcomp.pl>
Date: Fri, 17 May 2024 11:48:01 +0200
Subject: [PATCH] show error dialog in error handling middleware

---
 .../EditOverlayModal.component.test.tsx       |  7 ++
 .../hooks/useEditOverlay.test.ts              |  5 ++
 .../ErroReportModal.component.tsx             | 64 +++++++++++++++++++
 .../Modal/ErrorReportModal/index.ts           |  1 +
 .../FunctionalArea/Modal/Modal.component.tsx  |  6 ++
 .../utils/getBasePublications.test.ts         | 12 ++--
 .../utils/getBasePublications.ts              | 14 ++--
 .../utils/fetchElementData.ts                 | 18 ++++--
 .../LoadPluginFromUrl.component.test.tsx      | 14 ++--
 .../hooks/useLoadPluginFromUrl.ts             | 11 ++--
 .../Map/MapViewer/utils/useOlMap.ts           |  6 ++
 .../middlewares/error.middleware.test.ts      | 63 +++++++++++-------
 src/redux/middlewares/error.middleware.ts     | 14 ++--
 src/redux/modal/modal.constants.ts            |  1 +
 src/redux/modal/modal.mock.ts                 |  1 +
 src/redux/modal/modal.reducers.ts             | 13 ++++
 src/redux/modal/modal.slice.ts                |  3 +
 src/redux/modal/modal.types.ts                |  6 ++
 src/types/modal.ts                            |  1 +
 src/utils/error-report/errorReporting.ts      | 17 ++---
 .../getErrorMessage.constants.ts              |  1 +
 21 files changed, 214 insertions(+), 64 deletions(-)
 create mode 100644 src/components/FunctionalArea/Modal/ErrorReportModal/ErroReportModal.component.tsx
 create mode 100644 src/components/FunctionalArea/Modal/ErrorReportModal/index.ts

diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
index 6bda59af..b8015a4b 100644
--- a/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
@@ -46,6 +46,7 @@ describe('EditOverlayModal - component', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
     });
 
@@ -63,6 +64,7 @@ describe('EditOverlayModal - component', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
     });
 
@@ -92,6 +94,7 @@ describe('EditOverlayModal - component', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -126,6 +129,7 @@ describe('EditOverlayModal - component', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -161,6 +165,7 @@ describe('EditOverlayModal - component', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -195,6 +200,7 @@ describe('EditOverlayModal - component', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -223,6 +229,7 @@ describe('EditOverlayModal - component', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
     });
 
diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
index 3d4c31f1..172a1026 100644
--- a/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
@@ -23,6 +23,7 @@ describe('useEditOverlay', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
     });
 
@@ -58,6 +59,7 @@ describe('useEditOverlay', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
     });
 
@@ -96,6 +98,7 @@ describe('useEditOverlay', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
     });
 
@@ -130,6 +133,7 @@ describe('useEditOverlay', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
     });
 
@@ -165,6 +169,7 @@ describe('useEditOverlay', () => {
         editOverlayState: overlayFixture,
         molArtState: {},
         overviewImagesState: {},
+        errorReportState: {},
       },
     });
 
diff --git a/src/components/FunctionalArea/Modal/ErrorReportModal/ErroReportModal.component.tsx b/src/components/FunctionalArea/Modal/ErrorReportModal/ErroReportModal.component.tsx
new file mode 100644
index 00000000..819ac4b3
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/ErrorReportModal/ErroReportModal.component.tsx
@@ -0,0 +1,64 @@
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { getAllUserOverlaysByCreator } from '@/redux/overlays/overlays.thunks';
+import { loadingUserSelector } from '@/redux/user/user.selectors';
+import { login } from '@/redux/user/user.thunks';
+import { Button } from '@/shared/Button';
+import { Input } from '@/shared/Input';
+import React from 'react';
+
+export const ErrorReportModal: React.FC = () => {
+  const dispatch = useAppDispatch();
+  const loadingUser = useAppSelector(loadingUserSelector);
+  const isPending = loadingUser === 'pending';
+  const [credentials, setCredentials] = React.useState({ login: '', password: '' });
+
+  const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
+    const { name, value } = e.target;
+    setCredentials(prevCredentials => ({ ...prevCredentials, [name]: value }));
+  };
+
+  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>): Promise<void> => {
+    e.preventDefault();
+    await dispatch(login(credentials));
+    dispatch(getAllUserOverlaysByCreator());
+  };
+
+  return (
+    <div className="w-[400px] border border-t-[#E1E0E6] bg-white p-[24px]">
+      <form onSubmit={handleSubmit}>
+        <label className="mb-5 block text-sm font-semibold" htmlFor="login">
+          Hi there:
+          <Input
+            type="text"
+            name="login"
+            id="login"
+            placeholder="Your login here.."
+            value={credentials.login}
+            onChange={handleChange}
+            className="mt-2.5 text-sm font-medium text-font-400"
+          />
+        </label>
+        <label className="text-sm font-semibold" htmlFor="password">
+          Hmm:
+          <Input
+            type="password"
+            name="password"
+            id="password"
+            placeholder="Your password here.."
+            value={credentials.password}
+            onChange={handleChange}
+            className="mt-2.5 text-sm font-medium text-font-400"
+          />
+        </label>
+        <Button
+          type="submit"
+          className="w-full justify-center text-base font-medium"
+          disabled={isPending}
+        >
+          Submit
+        </Button>
+      </form>
+    </div>
+  );
+};
diff --git a/src/components/FunctionalArea/Modal/ErrorReportModal/index.ts b/src/components/FunctionalArea/Modal/ErrorReportModal/index.ts
new file mode 100644
index 00000000..016741c0
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/ErrorReportModal/index.ts
@@ -0,0 +1 @@
+export { ErrorReportModal } from './ErroReportModal.component';
diff --git a/src/components/FunctionalArea/Modal/Modal.component.tsx b/src/components/FunctionalArea/Modal/Modal.component.tsx
index 3fb3fb37..d913abb8 100644
--- a/src/components/FunctionalArea/Modal/Modal.component.tsx
+++ b/src/components/FunctionalArea/Modal/Modal.component.tsx
@@ -3,6 +3,7 @@ import { modalSelector } from '@/redux/modal/modal.selector';
 import dynamic from 'next/dynamic';
 import { EditOverlayModal } from './EditOverlayModal';
 import { LoginModal } from './LoginModal';
+import { ErrorReportModal } from './ErrorReportModal';
 import { ModalLayout } from './ModalLayout';
 import { OverviewImagesModal } from './OverviewImagesModal';
 import { PublicationsModal } from './PublicationsModal';
@@ -33,6 +34,11 @@ export const Modal = (): React.ReactNode => {
           <LoginModal />
         </ModalLayout>
       )}
+      {isOpen && modalName === 'error-report' && (
+        <ModalLayout>
+          <ErrorReportModal />
+        </ModalLayout>
+      )}
       {isOpen && modalName === 'publications' && <PublicationsModal />}
       {isOpen && modalName === 'edit-overlay' && (
         <ModalLayout>
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.test.ts b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.test.ts
index e29e23ec..ffa8191a 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.test.ts
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.test.ts
@@ -1,13 +1,13 @@
 import { apiPath } from '@/redux/apiPath';
 import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
 import { HttpStatusCode } from 'axios';
-import { handleError } from '@/utils/error-report/errorReporting';
+import { showToast } from '@/utils/showToast';
 import { PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK } from '../../../../../../models/mocks/publicationsResponseMock';
 import { getBasePublications } from './getBasePublications';
 
 const mockedAxiosClient = mockNetworkResponse();
 
-jest.mock('./../../../../../../utils/error-report/errorReporting');
+jest.mock('./../../../../../../utils/showToast');
 
 describe('getBasePublications - util', () => {
   const length = 10;
@@ -32,7 +32,7 @@ describe('getBasePublications - util', () => {
     expect(result).toStrictEqual([]);
   });
 
-  it('should return empty array and handle error if http error', async () => {
+  it('should return empty array and show toast error if http error', async () => {
     mockedAxiosClient
       .onGet(apiPath.getPublications({ params: { length } }))
       .reply(HttpStatusCode.BadRequest);
@@ -40,6 +40,10 @@ describe('getBasePublications - util', () => {
     const result = await getBasePublications({ length });
 
     expect(result).toStrictEqual([]);
-    expect(handleError).toHaveBeenCalled();
+    expect(showToast).toHaveBeenCalledWith({
+      message:
+        "Problem with fetching publications: The server couldn't understand your request. Please check your input and try again.",
+      type: 'error',
+    });
   });
 });
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.ts b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.ts
index a927bb14..d149d031 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.ts
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.ts
@@ -4,9 +4,8 @@ import { PUBLICATIONS_FETCHING_ERROR_PREFIX } from '@/redux/publications/publica
 import { axiosInstance } from '@/services/api/utils/axiosInstance';
 import { Publication, PublicationsResponse } from '@/types/models';
 import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
-import { getError } from '@/utils/error-report/getError';
-import { handleError } from '@/utils/error-report/errorReporting';
-import { store } from '@/redux/store';
+import { getErrorMessage } from '@/utils/getErrorMessage';
+import { showToast } from '@/utils/showToast';
 
 interface Args {
   length: number;
@@ -22,10 +21,11 @@ export const getBasePublications = async ({ length }: Args): Promise<Publication
 
     return isDataValid ? response.data.data : [];
   } catch (error) {
-    await handleError(
-      getError({ error, prefix: PUBLICATIONS_FETCHING_ERROR_PREFIX }),
-      store.getState(),
-    );
+    const errorMessage = getErrorMessage({ error, prefix: PUBLICATIONS_FETCHING_ERROR_PREFIX });
+    showToast({
+      type: 'error',
+      message: errorMessage,
+    });
     return [];
   }
 };
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/utils/fetchElementData.ts b/src/components/FunctionalArea/Modal/PublicationsModal/utils/fetchElementData.ts
index 3df91509..d7b14ea9 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/utils/fetchElementData.ts
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/utils/fetchElementData.ts
@@ -5,9 +5,8 @@ import { BIO_ENTITY_FETCHING_ERROR_PREFIX } from '@/redux/bioEntity/bioEntity.co
 import { axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance';
 import { BioEntityContent, BioEntityResponse } from '@/types/models';
 import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
-import { getError } from '@/utils/error-report/getError';
-import { handleError } from '@/utils/error-report/errorReporting';
-import { store } from '@/redux/store';
+import { showToast } from '@/utils/showToast';
+import { getErrorMessage } from '@/utils/getErrorMessage';
 
 export const fetchElementData = async (
   searchQuery: string,
@@ -26,10 +25,15 @@ export const fetchElementData = async (
       return response.data.content[FIRST_ARRAY_ELEMENT];
     }
   } catch (error) {
-    await handleError(
-      getError({ error, prefix: BIO_ENTITY_FETCHING_ERROR_PREFIX }),
-      store.getState(),
-    );
+    const errorMessage = getErrorMessage({
+      error,
+      prefix: BIO_ENTITY_FETCHING_ERROR_PREFIX,
+    });
+
+    showToast({
+      type: 'error',
+      message: errorMessage,
+    });
   }
 
   return undefined;
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.test.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.test.tsx
index c5c47d94..162b4545 100644
--- a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.test.tsx
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.test.tsx
@@ -9,13 +9,13 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
 import axios, { HttpStatusCode } from 'axios';
 import MockAdapter from 'axios-mock-adapter';
 import { act } from 'react-dom/test-utils';
-import { handleError } from '@/utils/error-report/errorReporting';
+import { showToast } from '@/utils/showToast';
 import { LoadPluginFromUrl } from './LoadPluginFromUrl.component';
 
 const mockedAxiosApiClient = mockNetworkResponse();
 const mockedAxiosClient = new MockAdapter(axios);
 
-jest.mock('../../../../../utils/error-report/errorReporting');
+jest.mock('../../../../../utils/showToast');
 
 const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => {
   const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
@@ -116,13 +116,14 @@ describe('LoadPluginFromUrl - component', () => {
       const button = screen.getByTestId('load-plugin-button');
       expect(button).toBeDisabled();
     });
-    it('should handle error if plugin failed to load', async () => {
+    it('should show toast if plugin failed to load', async () => {
       const pluginUrl = 'http://example.com/plugin.js';
       mockedAxiosClient.onGet(pluginUrl).reply(HttpStatusCode.Unauthorized, null);
 
       global.URL.canParse = jest.fn().mockReturnValue(true);
 
       renderComponent();
+
       const input = screen.getByTestId('load-plugin-input-url');
       expect(input).toBeVisible();
 
@@ -137,7 +138,12 @@ describe('LoadPluginFromUrl - component', () => {
       });
 
       await waitFor(() => {
-        expect(handleError).toHaveBeenCalled();
+        expect(showToast).toHaveBeenCalled();
+        expect(showToast).toHaveBeenCalledWith({
+          message:
+            "Failed to load plugin: You're not authorized to access this resource. Please log in or check your credentials.",
+          type: 'error',
+        });
       });
     });
 
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/hooks/useLoadPluginFromUrl.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/hooks/useLoadPluginFromUrl.ts
index 23f6c19e..5616dca8 100644
--- a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/hooks/useLoadPluginFromUrl.ts
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/hooks/useLoadPluginFromUrl.ts
@@ -2,9 +2,8 @@ import { PluginsManager } from '@/services/pluginsManager';
 import axios from 'axios';
 import { ChangeEvent, useMemo, useState, KeyboardEvent } from 'react';
 import { ENTER_KEY_CODE } from '@/constants/common';
-import { getError } from '@/utils/error-report/getError';
-import { handleError } from '@/utils/error-report/errorReporting';
-import { store } from '@/redux/store';
+import { showToast } from '@/utils/showToast';
+import { getErrorMessage } from '@/utils/getErrorMessage';
 import { PLUGIN_LOADING_ERROR_PREFIX } from '../../AvailablePluginsDrawer.constants';
 
 type UseLoadPluginReturnType = {
@@ -44,7 +43,11 @@ export const useLoadPluginFromUrl = (): UseLoadPluginReturnType => {
 
       setPluginUrl('');
     } catch (error) {
-      await handleError(getError({ error, prefix: PLUGIN_LOADING_ERROR_PREFIX }), store.getState());
+      const errorMessage = getErrorMessage({ error, prefix: PLUGIN_LOADING_ERROR_PREFIX });
+      showToast({
+        type: 'error',
+        message: errorMessage,
+      });
     } finally {
       setIsLoading(false);
     }
diff --git a/src/components/Map/MapViewer/utils/useOlMap.ts b/src/components/Map/MapViewer/utils/useOlMap.ts
index 49ec3002..4214f1fd 100644
--- a/src/components/Map/MapViewer/utils/useOlMap.ts
+++ b/src/components/Map/MapViewer/utils/useOlMap.ts
@@ -20,7 +20,13 @@ type UseOlMap = (input?: UseOlMapInput) => UseOlMapOutput;
 export const useOlMap: UseOlMap = ({ target } = {}) => {
   const mapRef = React.useRef<null | HTMLDivElement>(null);
   const { mapInstance, handleSetMapInstance } = useMapInstance();
+  // eslint-disable-next-line no-console
+  console.log('!!!!!!!!!!');
+  // eslint-disable-next-line no-console
+  console.log(mapInstance);
   const view = useOlMapView({ mapInstance });
+  // eslint-disable-next-line no-console
+  console.log(view);
   useOlMapLayers({ mapInstance });
   useOlMapListeners({ view, mapInstance });
 
diff --git a/src/redux/middlewares/error.middleware.test.ts b/src/redux/middlewares/error.middleware.test.ts
index 76362550..21bc72d7 100644
--- a/src/redux/middlewares/error.middleware.test.ts
+++ b/src/redux/middlewares/error.middleware.test.ts
@@ -1,13 +1,8 @@
-import { handleError } from '@/utils/error-report/errorReporting';
 import { store } from '@/redux/store';
 import { errorMiddlewareListener } from './error.middleware';
 
-jest.mock('../../utils/error-report/errorReporting', () => ({
-  handleError: jest.fn(),
-}));
-
 describe('errorMiddlewareListener', () => {
-  // eslint-disable-next-line no-console
+  const dispatchSpy = jest.spyOn(store, 'dispatch');
 
   beforeEach(() => {
     jest.clearAllMocks();
@@ -26,14 +21,19 @@ describe('errorMiddlewareListener', () => {
         code: 'Error 2',
       },
     };
-    const { getState } = store;
+    const { getState, dispatch } = store;
     // eslint-disable-next-line @typescript-eslint/ban-ts-comment
     // @ts-expect-error
-    await errorMiddlewareListener(action, { getState });
-    expect(handleError).toHaveBeenCalledWith({ code: 'Error 2' }, getState());
+    await errorMiddlewareListener(action, { getState, dispatch });
+    expect(dispatchSpy).toHaveBeenCalledWith(
+      expect.objectContaining({
+        type: 'modal/openErrorReportModal',
+        payload: expect.anything(),
+      }),
+    );
   });
 
-  it('should handle error without message when action is rejected without value', async () => {
+  it('should handle error without message when action is rejected', async () => {
     const action = {
       type: 'action/rejected',
       payload: null,
@@ -46,11 +46,16 @@ describe('errorMiddlewareListener', () => {
         code: 'Error 3',
       },
     };
-    const { getState } = store;
+    const { getState, dispatch } = store;
     // eslint-disable-next-line @typescript-eslint/ban-ts-comment
     // @ts-expect-error
-    await errorMiddlewareListener(action, { getState });
-    expect(handleError).toHaveBeenCalledWith({ code: 'Error 3' }, getState());
+    await errorMiddlewareListener(action, { getState, dispatch });
+    expect(dispatchSpy).toHaveBeenCalledWith(
+      expect.objectContaining({
+        type: 'modal/openErrorReportModal',
+        payload: expect.anything(),
+      }),
+    );
   });
 
   it('should not handle error when action is not rejected', async () => {
@@ -62,11 +67,11 @@ describe('errorMiddlewareListener', () => {
         requestStatus: 'fulfilled',
       },
     };
-    const { getState } = store;
+    const { getState, dispatch } = store;
     // eslint-disable-next-line @typescript-eslint/ban-ts-comment
     // @ts-expect-error
-    await errorMiddlewareListener(action, { getState });
-    expect(handleError).not.toHaveBeenCalled();
+    await errorMiddlewareListener(action, { getState, dispatch });
+    expect(dispatchSpy).not.toHaveBeenCalled();
   });
 
   it('should handle error with unknown error message when action payload is not a string', async () => {
@@ -83,13 +88,15 @@ describe('errorMiddlewareListener', () => {
         message: 'Error message',
       },
     };
-    const { getState } = store;
+    const { getState, dispatch } = store;
     // eslint-disable-next-line @typescript-eslint/ban-ts-comment
     // @ts-expect-error
-    await errorMiddlewareListener(action, { getState });
-    expect(handleError).toHaveBeenCalledWith(
-      { code: 'ERROR', message: 'Error message' },
-      getState(),
+    await errorMiddlewareListener(action, { getState, dispatch });
+    expect(dispatchSpy).toHaveBeenCalledWith(
+      expect.objectContaining({
+        type: 'modal/openErrorReportModal',
+        payload: expect.anything(),
+      }),
     );
   });
 
@@ -105,12 +112,20 @@ describe('errorMiddlewareListener', () => {
       error: {
         code: 'ERROR',
         message: 'xyz',
+        stack: 'stack',
       },
     };
-    const { getState } = store;
+    const { getState, dispatch } = store;
     // eslint-disable-next-line @typescript-eslint/ban-ts-comment
     // @ts-expect-error
-    await errorMiddlewareListener(action, { getState });
-    expect(handleError).toHaveBeenCalledWith({ code: 'ERROR', message: 'xyz' }, getState());
+    await errorMiddlewareListener(action, { getState, dispatch });
+    expect(dispatchSpy).toHaveBeenCalledWith(
+      expect.objectContaining({
+        type: 'modal/openErrorReportModal',
+        payload: expect.objectContaining({
+          stacktrace: 'stack',
+        }),
+      }),
+    );
   });
 });
diff --git a/src/redux/middlewares/error.middleware.ts b/src/redux/middlewares/error.middleware.ts
index 3466c17c..e9f21c3b 100644
--- a/src/redux/middlewares/error.middleware.ts
+++ b/src/redux/middlewares/error.middleware.ts
@@ -1,6 +1,7 @@
 import type { AppListenerEffectAPI, AppStartListening } from '@/redux/store';
 import { Action, createListenerMiddleware, isRejected } from '@reduxjs/toolkit';
-import { handleError } from '@/utils/error-report/errorReporting';
+import { createErrorData } from '@/utils/error-report/errorReporting';
+import { openErrorReportModal } from '@/redux/modal/modal.slice';
 
 export const errorListenerMiddleware = createListenerMiddleware();
 
@@ -8,10 +9,15 @@ const startListening = errorListenerMiddleware.startListening as AppStartListeni
 
 export const errorMiddlewareListener = async (
   action: Action,
-  { getState }: AppListenerEffectAPI,
+  { getState, dispatch }: AppListenerEffectAPI,
 ): Promise<void> => {
-  if (isRejected(action)) {
-    await handleError(action.error, getState());
+  if (isRejected(action) && action.type !== 'user/getSessionValid/rejected') {
+    // eslint-disable-next-line no-console
+    console.log(action);
+    const errorData = await createErrorData(action.error, getState());
+    // eslint-disable-next-line no-console
+    console.log(errorData);
+    dispatch(openErrorReportModal(errorData));
   }
 };
 
diff --git a/src/redux/modal/modal.constants.ts b/src/redux/modal/modal.constants.ts
index f0df9964..d7dea45c 100644
--- a/src/redux/modal/modal.constants.ts
+++ b/src/redux/modal/modal.constants.ts
@@ -12,4 +12,5 @@ export const MODAL_INITIAL_STATE: ModalState = {
     uniprotId: MOL_ART_UNIPROT_ID_DEFAULT,
   },
   editOverlayState: null,
+  errorReportState: {},
 };
diff --git a/src/redux/modal/modal.mock.ts b/src/redux/modal/modal.mock.ts
index 22b83303..cde5fab5 100644
--- a/src/redux/modal/modal.mock.ts
+++ b/src/redux/modal/modal.mock.ts
@@ -12,4 +12,5 @@ export const MODAL_INITIAL_STATE_MOCK: ModalState = {
     uniprotId: MOL_ART_UNIPROT_ID_DEFAULT,
   },
   editOverlayState: null,
+  errorReportState: {},
 };
diff --git a/src/redux/modal/modal.reducers.ts b/src/redux/modal/modal.reducers.ts
index 4871a245..b32a6c4d 100644
--- a/src/redux/modal/modal.reducers.ts
+++ b/src/redux/modal/modal.reducers.ts
@@ -1,5 +1,6 @@
 import { ModalName } from '@/types/modal';
 import { PayloadAction } from '@reduxjs/toolkit';
+import { ErrorData } from '@/utils/error-report/ErrorData';
 import { ModalState, OpenEditOverlayModalAction } from './modal.types';
 
 export const openModalReducer = (state: ModalState, action: PayloadAction<ModalName>): void => {
@@ -48,6 +49,18 @@ export const openLoggedInMenuModalReducer = (state: ModalState): void => {
   state.modalTitle = 'Select';
 };
 
+export const openErrorReportModalReducer = (
+  state: ModalState,
+  action: PayloadAction<ErrorData | undefined>,
+): void => {
+  state.isOpen = true;
+  state.modalName = 'error-report';
+  state.modalTitle = 'Error Report';
+  state.errorReportState = {
+    errorData: action.payload,
+  };
+};
+
 export const setOverviewImageIdReducer = (
   state: ModalState,
   action: PayloadAction<number>,
diff --git a/src/redux/modal/modal.slice.ts b/src/redux/modal/modal.slice.ts
index c1fe7b36..40f7ed65 100644
--- a/src/redux/modal/modal.slice.ts
+++ b/src/redux/modal/modal.slice.ts
@@ -10,6 +10,7 @@ import {
   openPublicationsModalReducer,
   openEditOverlayModalReducer,
   openLoggedInMenuModalReducer,
+  openErrorReportModalReducer,
 } from './modal.reducers';
 
 const modalSlice = createSlice({
@@ -25,6 +26,7 @@ const modalSlice = createSlice({
     openPublicationsModal: openPublicationsModalReducer,
     openEditOverlayModal: openEditOverlayModalReducer,
     openLoggedInMenuModal: openLoggedInMenuModalReducer,
+    openErrorReportModal: openErrorReportModalReducer,
   },
 });
 
@@ -38,6 +40,7 @@ export const {
   openPublicationsModal,
   openEditOverlayModal,
   openLoggedInMenuModal,
+  openErrorReportModal,
 } = modalSlice.actions;
 
 export default modalSlice.reducer;
diff --git a/src/redux/modal/modal.types.ts b/src/redux/modal/modal.types.ts
index dfb5ca5d..ea772096 100644
--- a/src/redux/modal/modal.types.ts
+++ b/src/redux/modal/modal.types.ts
@@ -1,6 +1,7 @@
 import { ModalName } from '@/types/modal';
 import { MapOverlay } from '@/types/models';
 import { PayloadAction } from '@reduxjs/toolkit';
+import { ErrorData } from '@/utils/error-report/ErrorData';
 
 export type OverviewImagesModalState = {
   imageId?: number;
@@ -10,6 +11,10 @@ export type MolArtModalState = {
   uniprotId?: string | undefined;
 };
 
+export type ErrorRepostState = {
+  errorData?: ErrorData | undefined;
+};
+
 export type EditOverlayState = MapOverlay | null;
 
 export interface ModalState {
@@ -18,6 +23,7 @@ export interface ModalState {
   modalTitle: string;
   overviewImagesState: OverviewImagesModalState;
   molArtState: MolArtModalState;
+  errorReportState: ErrorRepostState;
   editOverlayState: EditOverlayState;
 }
 
diff --git a/src/types/modal.ts b/src/types/modal.ts
index b268bf17..865adda9 100644
--- a/src/types/modal.ts
+++ b/src/types/modal.ts
@@ -5,4 +5,5 @@ export type ModalName =
   | 'login'
   | 'publications'
   | 'edit-overlay'
+  | 'error-report'
   | 'logged-in-menu';
diff --git a/src/utils/error-report/errorReporting.ts b/src/utils/error-report/errorReporting.ts
index 40488af9..e457bc5c 100644
--- a/src/utils/error-report/errorReporting.ts
+++ b/src/utils/error-report/errorReporting.ts
@@ -2,6 +2,7 @@ import { ErrorData } from '@/utils/error-report/ErrorData';
 import { SerializedError } from '@reduxjs/toolkit';
 import { ONE_THOUSAND } from '@/constants/common';
 import {
+  GENERIC_AXIOS_ERROR_CODE,
   UNKNOWN_AXIOS_ERROR_CODE,
   UNKNOWN_ERROR,
 } from '@/utils/getErrorMessage/getErrorMessage.constants';
@@ -41,7 +42,12 @@ export const createErrorData = async (
   let javaStacktrace = null;
   if (error !== undefined && 'code' in error) {
     const { code } = error;
-    if (code && code !== UNKNOWN_ERROR && code !== UNKNOWN_AXIOS_ERROR_CODE) {
+    if (
+      code &&
+      code !== UNKNOWN_ERROR &&
+      code !== UNKNOWN_AXIOS_ERROR_CODE &&
+      code !== GENERIC_AXIOS_ERROR_CODE
+    ) {
       try {
         javaStacktrace = (await axiosInstance.get<JavaStacktrace>(apiPath.getStacktrace(code))).data
           .content;
@@ -64,12 +70,3 @@ export const createErrorData = async (
     version,
   };
 };
-
-export const handleError = async (
-  error: Error | SerializedError | undefined,
-  state: RootState,
-): Promise<void> => {
-  const errorData = await createErrorData(error, state);
-  // eslint-disable-next-line no-console
-  console.log(errorData);
-};
diff --git a/src/utils/getErrorMessage/getErrorMessage.constants.ts b/src/utils/getErrorMessage/getErrorMessage.constants.ts
index d3cba2ab..406df75f 100644
--- a/src/utils/getErrorMessage/getErrorMessage.constants.ts
+++ b/src/utils/getErrorMessage/getErrorMessage.constants.ts
@@ -1,5 +1,6 @@
 export const UNKNOWN_ERROR = 'An unknown error occurred. Please try again later.';
 export const UNKNOWN_AXIOS_ERROR_CODE = 'UNKNOWN_AXIOS_ERROR';
+export const GENERIC_AXIOS_ERROR_CODE = 'ERR_BAD_REQUEST';
 
 export const HTTP_ERROR_MESSAGES = {
   400: "The server couldn't understand your request. Please check your input and try again.",
-- 
GitLab