diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8b9f9178f75ec0851bfd69bd93797d87ce59f12f
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts
@@ -0,0 +1,25 @@
+import { PinType } from '@/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types';
+import { ONE } from '@/constants/common';
+import { BioEntity } from '@/types/models';
+import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
+import { Feature } from 'ol';
+import { getBioEntitySingleFeature } from './getBioEntitySingleFeature';
+
+export const getBioEntitiesFeatures = (
+  bioEntites: BioEntity[],
+  {
+    pointToProjection,
+    type,
+  }: {
+    pointToProjection: UsePointToProjectionResult;
+    type: PinType;
+  },
+): Feature[] => {
+  return bioEntites.map((bioEntity, index) =>
+    getBioEntitySingleFeature(bioEntity, {
+      pointToProjection,
+      type,
+      value: index + ONE,
+    }),
+  );
+};
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntititesFeatures.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntititesFeatures.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6c0eb2e3a1619022fd9ef785c0b94d49b011012a
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntititesFeatures.test.ts
@@ -0,0 +1,45 @@
+import { PinType } from '@/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types';
+import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture';
+import { initialMapStateFixture } from '@/redux/map/map.fixtures';
+import { UsePointToProjectionResult, usePointToProjection } from '@/utils/map/usePointToProjection';
+import {
+  GetReduxWrapperUsingSliceReducer,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
+import { Feature } from 'ol';
+import Style from 'ol/style/Style';
+import { getBioEntitiesFeatures } from './getBioEntitiesFeatures';
+
+const getPointToProjection = (
+  wrapper: ReturnType<GetReduxWrapperUsingSliceReducer>['Wrapper'],
+): UsePointToProjectionResult => {
+  const { result: usePointToProjectionHook } = renderHook(() => usePointToProjection(), {
+    wrapper,
+  });
+
+  return usePointToProjectionHook.current;
+};
+
+describe('getBioEntitiesFeatures - subUtil', () => {
+  const { Wrapper } = getReduxWrapperWithStore({
+    map: initialMapStateFixture,
+  });
+  const bioEntititesContent = bioEntitiesContentFixture;
+  const bioEntities = bioEntititesContent.map(({ bioEntity }) => bioEntity);
+  const pointToProjection = getPointToProjection(Wrapper);
+
+  const pinTypes: PinType[] = ['bioEntity', 'drugs', 'chemicals', 'mirna', 'none'];
+
+  it.each(pinTypes)('should return array of instances of Feature with Style type=%s', type => {
+    const result = getBioEntitiesFeatures(bioEntities, {
+      pointToProjection,
+      type,
+    });
+
+    result.forEach(resultElement => {
+      expect(resultElement).toBeInstanceOf(Feature);
+      expect(resultElement.getStyle()).toBeInstanceOf(Style);
+    });
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..79d66146891233a301d9528594bc2e8020e8d47e
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.test.ts
@@ -0,0 +1,66 @@
+import { PinType } from '@/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types';
+import { PINS_COLORS } from '@/constants/canvas';
+import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture';
+import { initialMapStateFixture } from '@/redux/map/map.fixtures';
+import { UsePointToProjectionResult, usePointToProjection } from '@/utils/map/usePointToProjection';
+import {
+  GetReduxWrapperUsingSliceReducer,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
+import { Feature } from 'ol';
+import Style from 'ol/style/Style';
+import { getBioEntitySingleFeature } from './getBioEntitySingleFeature';
+import * as getPinStyle from './getPinStyle';
+
+jest.mock('./getPinStyle', () => ({
+  __esModule: true,
+  ...jest.requireActual('./getPinStyle'),
+}));
+
+const getPinStyleSpy = jest.spyOn(getPinStyle, 'getPinStyle');
+
+const getPointToProjection = (
+  wrapper: ReturnType<GetReduxWrapperUsingSliceReducer>['Wrapper'],
+): UsePointToProjectionResult => {
+  const { result: usePointToProjectionHook } = renderHook(() => usePointToProjection(), {
+    wrapper,
+  });
+
+  return usePointToProjectionHook.current;
+};
+
+describe('getBioEntitySingleFeature - subUtil', () => {
+  const { Wrapper } = getReduxWrapperWithStore({
+    map: initialMapStateFixture,
+  });
+  const { bioEntity } = bioEntityContentFixture;
+  const pointToProjection = getPointToProjection(Wrapper);
+
+  const value = 1448;
+  const pinTypes: PinType[] = ['bioEntity', 'drugs', 'chemicals', 'mirna', 'none'];
+
+  it.each(pinTypes)('should return instance of Feature with Style type=%s', type => {
+    const result = getBioEntitySingleFeature(bioEntity, {
+      pointToProjection,
+      type,
+      value,
+    });
+
+    expect(result).toBeInstanceOf(Feature);
+    expect(result.getStyle()).toBeInstanceOf(Style);
+  });
+
+  it.each(pinTypes)('should run getPinStyle with valid args for type=%s', async type => {
+    getBioEntitySingleFeature(bioEntity, {
+      pointToProjection,
+      type,
+      value,
+    });
+
+    expect(getPinStyleSpy).toHaveBeenCalledWith({
+      color: PINS_COLORS[type],
+      value,
+    });
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b910627e271eeb0d4ea7717e5ed9ea6bc56aabb3
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.ts
@@ -0,0 +1,29 @@
+import { PinType } from '@/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types';
+import { PINS_COLORS } from '@/constants/canvas';
+import { BioEntity } from '@/types/models';
+import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
+import { Feature } from 'ol';
+import { getPinFeature } from './getPinFeature';
+import { getPinStyle } from './getPinStyle';
+
+export const getBioEntitySingleFeature = (
+  bioEntity: BioEntity,
+  {
+    pointToProjection,
+    type,
+    value,
+  }: {
+    pointToProjection: UsePointToProjectionResult;
+    type: PinType;
+    value: number;
+  },
+): Feature => {
+  const feature = getPinFeature(bioEntity, pointToProjection);
+  const style = getPinStyle({
+    color: PINS_COLORS[type],
+    value,
+  });
+
+  feature.setStyle(style);
+  return feature;
+};
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..64f3decc886751a4913a9d1b04cb0ff53241270b
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.test.ts
@@ -0,0 +1,38 @@
+import { HALF } from '@/constants/dividers';
+import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture';
+import { initialMapStateFixture } from '@/redux/map/map.fixtures';
+import { usePointToProjection } from '@/utils/map/usePointToProjection';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
+import { Feature } from 'ol';
+import { getPinFeature } from './getPinFeature';
+
+describe('getPinFeature - subUtil', () => {
+  const { Wrapper } = getReduxWrapperWithStore({
+    map: initialMapStateFixture,
+  });
+  const { bioEntity } = bioEntityContentFixture;
+  const { result: usePointToProjectionHook } = renderHook(() => usePointToProjection(), {
+    wrapper: Wrapper,
+  });
+  const pointToProjection = usePointToProjectionHook.current;
+  const result = getPinFeature(bioEntity, pointToProjection);
+
+  it('should return instance of Feature', () => {
+    expect(result).toBeInstanceOf(Feature);
+  });
+
+  it('should return id as name', () => {
+    expect(result.get('name')).toBe(bioEntity.id);
+  });
+
+  it('should return point parsed with point to projection', () => {
+    const [x, y] = result.getGeometry()?.getExtent() || [];
+    const geometryPoint = pointToProjection({
+      x: bioEntity.x + bioEntity.width / HALF,
+      y: bioEntity.y + bioEntity.height / HALF,
+    });
+
+    expect([x, y]).toStrictEqual(geometryPoint);
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ec09a90d48d11cf3d2f743fca21bbd5f1475244b
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts
@@ -0,0 +1,20 @@
+import { HALF } from '@/constants/dividers';
+import { BioEntity } from '@/types/models';
+import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
+import { Feature } from 'ol';
+import { Point } from 'ol/geom';
+
+export const getPinFeature = (
+  { x, y, width, height, id }: BioEntity,
+  pointToProjection: UsePointToProjectionResult,
+): Feature => {
+  const point = {
+    x: x + width / HALF,
+    y: y + height / HALF,
+  };
+
+  return new Feature({
+    geometry: new Point(pointToProjection(point)),
+    name: id,
+  });
+};
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getPinStyle.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinStyle.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..add22cbf0eb2d01e969e0dd421bbf9eafe462fc7
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinStyle.test.ts
@@ -0,0 +1,27 @@
+import { PIN_SIZE } from '@/constants/canvas';
+import { ZERO } from '@/constants/common';
+import Style from 'ol/style/Style';
+import { getPinStyle } from './getPinStyle';
+
+describe('getPinStyle - subUtil', () => {
+  const input = {
+    color: '#000000',
+    value: 420,
+  };
+
+  const result = getPinStyle(input);
+
+  it('should return instance of Style', () => {
+    expect(result).toBeInstanceOf(Style);
+  });
+
+  it('should return image object with displacament of pin size height', () => {
+    const image = result.getImage();
+    expect(image.getDisplacement()).toStrictEqual([ZERO, PIN_SIZE.height]);
+  });
+
+  it('should return image of pin size', () => {
+    const image = result.getImage();
+    expect(image.getImageSize()).toStrictEqual([PIN_SIZE.width, PIN_SIZE.height]);
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getPinStyle.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinStyle.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3e91dfc047c45e2d6ac6a872564028abe8deb2d7
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinStyle.ts
@@ -0,0 +1,18 @@
+import { PIN_SIZE } from '@/constants/canvas';
+import { ZERO } from '@/constants/common';
+import Icon from 'ol/style/Icon';
+import Style from 'ol/style/Style';
+import { getCanvasIcon } from '../getCanvasIcon';
+
+export const getPinStyle = ({ value, color }: { value: number; color: string }): Style =>
+  new Style({
+    image: new Icon({
+      displacement: [ZERO, PIN_SIZE.height],
+      anchorXUnits: 'fraction',
+      anchorYUnits: 'pixels',
+      img: getCanvasIcon({
+        color,
+        value,
+      }),
+    }),
+  });
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cfcbe85e373b7d8bc10bbfb927a83e7e1b3224e7
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.test.ts
@@ -0,0 +1,17 @@
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
+import VectorLayer from 'ol/layer/Vector';
+import { useOlMapPinsLayer } from './useOlMapPinsLayer';
+
+describe('useOlMapPinsLayer - util', () => {
+  const { Wrapper } = getReduxWrapperWithStore();
+
+  it('should return VectorLayer', () => {
+    const { result } = renderHook(() => useOlMapPinsLayer(), {
+      wrapper: Wrapper,
+    });
+
+    expect(result.current).toBeInstanceOf(VectorLayer);
+    expect(result.current.getSourceState()).toBe('ready');
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..51523f777916b3ef9d36b7d23d21f429d8f38f43
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts
@@ -0,0 +1,36 @@
+/* eslint-disable no-magic-numbers */
+import { allBioEntitesSelectorOfCurrentMap } from '@/redux/bioEntity/bioEntity.selectors';
+import { usePointToProjection } from '@/utils/map/usePointToProjection';
+import BaseLayer from 'ol/layer/Base';
+import VectorLayer from 'ol/layer/Vector';
+import VectorSource from 'ol/source/Vector';
+import { useMemo } from 'react';
+import { useSelector } from 'react-redux';
+import { getBioEntitiesFeatures } from './getBioEntitiesFeatures';
+
+export const useOlMapPinsLayer = (): BaseLayer => {
+  const pointToProjection = usePointToProjection();
+  const contentBioEntites = useSelector(allBioEntitesSelectorOfCurrentMap);
+
+  const bioEntityFeatures = useMemo(
+    () =>
+      [getBioEntitiesFeatures(contentBioEntites, { pointToProjection, type: 'bioEntity' })].flat(),
+    [contentBioEntites, pointToProjection],
+  );
+
+  const vectorSource = useMemo(() => {
+    return new VectorSource({
+      features: [...bioEntityFeatures],
+    });
+  }, [bioEntityFeatures]);
+
+  const pinsLayer = useMemo(
+    () =>
+      new VectorLayer({
+        source: vectorSource,
+      }),
+    [vectorSource],
+  );
+
+  return pinsLayer;
+};
diff --git a/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.test.ts b/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4857318954de7c35d8eed0637a372a4850861fdf
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.test.ts
@@ -0,0 +1,54 @@
+import { initialMapStateFixture } from '@/redux/map/map.fixtures';
+import { LinePoint } from '@/types/reactions';
+import { UsePointToProjectionResult, usePointToProjection } from '@/utils/map/usePointToProjection';
+import {
+  GetReduxWrapperUsingSliceReducer,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
+import { Feature } from 'ol';
+import { LineString } from 'ol/geom';
+import { getLineFeature } from './getLineFeature';
+
+const getPointToProjection = (
+  wrapper: ReturnType<GetReduxWrapperUsingSliceReducer>['Wrapper'],
+): UsePointToProjectionResult => {
+  const { result: usePointToProjectionHook } = renderHook(() => usePointToProjection(), {
+    wrapper,
+  });
+
+  return usePointToProjectionHook.current;
+};
+
+describe('getLineFeature', () => {
+  const { Wrapper } = getReduxWrapperWithStore({
+    map: initialMapStateFixture,
+  });
+  const pointToProjection = getPointToProjection(Wrapper);
+
+  const linePoints: LinePoint = [
+    {
+      x: 16,
+      y: 32,
+    },
+    {
+      x: 54,
+      y: 16,
+    },
+  ];
+
+  it('should return valid Feature object', () => {
+    const result = getLineFeature(linePoints, pointToProjection);
+
+    expect(result).toBeInstanceOf(Feature);
+  });
+
+  it('should return valid Feature object with LineString geometry', () => {
+    const result = getLineFeature(linePoints, pointToProjection);
+    const geometry = result.getGeometry();
+
+    expect(geometry).toBeInstanceOf(LineString);
+    // eslint-disable-next-line no-magic-numbers
+    expect(geometry?.getExtent()).toStrictEqual([Infinity, -238107693, Infinity, -238107693]);
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts b/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts
new file mode 100644
index 0000000000000000000000000000000000000000..40211171605c35ff87995e6ed9abf02bc300c76b
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts
@@ -0,0 +1,15 @@
+import { LinePoint } from '@/types/reactions';
+import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
+import { Feature } from 'ol';
+import { LineString } from 'ol/geom';
+
+export const getLineFeature = (
+  linePoints: LinePoint,
+  pointToProjection: UsePointToProjectionResult,
+): Feature => {
+  const points = linePoints.map(pointToProjection);
+
+  return new Feature({
+    geometry: new LineString(points),
+  });
+};
diff --git a/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.test.ts b/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..675e6b2fed86fba7182b4031ea80f1ddf5f06b5c
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.test.ts
@@ -0,0 +1,31 @@
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
+import VectorLayer from 'ol/layer/Vector';
+import Style from 'ol/style/Style';
+import { useOlMapReactionsLayer } from './useOlMapReactionsLayer';
+
+describe('useOlMapReactionsLayer - util', () => {
+  const { Wrapper } = getReduxWrapperWithStore();
+
+  it('should return VectorLayer', () => {
+    const { result } = renderHook(() => useOlMapReactionsLayer(), {
+      wrapper: Wrapper,
+    });
+
+    expect(result.current).toBeInstanceOf(VectorLayer);
+    expect(result.current.getSourceState()).toBe('ready');
+  });
+
+  it('should return VectorLayer with valid Style', () => {
+    const { result } = renderHook(() => useOlMapReactionsLayer(), {
+      wrapper: Wrapper,
+    });
+
+    const vectorLayer = result.current;
+    const style = vectorLayer.getStyle();
+
+    expect(style).not.toBeInstanceOf(Array);
+    expect((style as Style).getFill()).toEqual({ color_: '#00AAFF' });
+    expect((style as Style).getStroke()).toMatchObject({ color_: '#00AAFF', width_: 6 });
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts b/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3c4fbb6483e8b8bce865b2a5077846b28b637575
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
@@ -0,0 +1,49 @@
+/* eslint-disable no-magic-numbers */
+import { LINE_COLOR, LINE_WIDTH } from '@/constants/canvas';
+import { allReactionsSelectorOfCurrentMap } from '@/redux/reactions/reactions.selector';
+import { Reaction } from '@/types/models';
+import { LinePoint } from '@/types/reactions';
+import { usePointToProjection } from '@/utils/map/usePointToProjection';
+import Geometry from 'ol/geom/Geometry';
+import VectorLayer from 'ol/layer/Vector';
+import VectorSource from 'ol/source/Vector';
+import Fill from 'ol/style/Fill';
+import Stroke from 'ol/style/Stroke';
+import Style from 'ol/style/Style';
+import { useMemo } from 'react';
+import { useSelector } from 'react-redux';
+import { getLineFeature } from './getLineFeature';
+
+const getReactionsLines = (reactions: Reaction[]): LinePoint[] =>
+  reactions.map(({ lines }) => lines.map(({ start, end }): LinePoint => [start, end])).flat();
+
+export const useOlMapReactionsLayer = (): VectorLayer<VectorSource<Geometry>> => {
+  const pointToProjection = usePointToProjection();
+  const reactions = useSelector(allReactionsSelectorOfCurrentMap);
+  const reactionsLines = getReactionsLines(reactions);
+
+  const reactionsLinesFeatures = useMemo(
+    () => reactionsLines.map(linePoint => getLineFeature(linePoint, pointToProjection)),
+    [reactionsLines, pointToProjection],
+  );
+
+  const vectorSource = useMemo(() => {
+    return new VectorSource({
+      features: [...reactionsLinesFeatures],
+    });
+  }, [reactionsLinesFeatures]);
+
+  const reactionsLayer = useMemo(
+    () =>
+      new VectorLayer({
+        source: vectorSource,
+        style: new Style({
+          fill: new Fill({ color: LINE_COLOR }),
+          stroke: new Stroke({ color: LINE_COLOR, width: LINE_WIDTH }),
+        }),
+      }),
+    [vectorSource],
+  );
+
+  return reactionsLayer;
+};
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts b/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts
index c240ae88a5017c0108be17e74e272dcf84abe855..cee56323c59bb31a4071c527285eca44a37c9c44 100644
--- a/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts
+++ b/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts
@@ -1,16 +1,16 @@
 /* eslint-disable no-magic-numbers */
+import { BACKGROUND_INITIAL_STATE_MOCK } from '@/redux/backgrounds/background.mock';
 import { MAP_DATA_INITIAL_STATE, OPENED_MAPS_INITIAL_STATE } from '@/redux/map/map.constants';
-import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { initialMapStateFixture } from '@/redux/map/map.fixtures';
-import { BACKGROUND_INITIAL_STATE_MOCK } from '@/redux/backgrounds/background.mock';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { renderHook, waitFor } from '@testing-library/react';
 import { Map } from 'ol';
 import BaseLayer from 'ol/layer/Base';
 import TileLayer from 'ol/layer/Tile';
 import VectorLayer from 'ol/layer/Vector';
 import React from 'react';
-import { useOlMapLayers } from './useOlMapLayers';
 import { useOlMap } from '../useOlMap';
+import { useOlMapLayers } from './useOlMapLayers';
 
 const useRefValue = {
   current: null,
@@ -98,17 +98,24 @@ describe('useOlMapLayers - util', () => {
     return result.current;
   };
 
-  it('should return valid TileLayer instance', () => {
+  it('should return valid TileLayer instance [1]', () => {
     const result = getRenderedHookResults();
 
     expect(result[0]).toBeInstanceOf(TileLayer);
     expect(result[0].getSourceState()).toBe('ready');
   });
 
-  it('should return valid VectorLayer instance', () => {
+  it('should return valid VectorLayer instance [2]', () => {
     const result = getRenderedHookResults();
 
     expect(result[1]).toBeInstanceOf(VectorLayer);
     expect(result[1].getSourceState()).toBe('ready');
   });
+
+  it('should return valid VectorLayer instance [3]', () => {
+    const result = getRenderedHookResults();
+
+    expect(result[2]).toBeInstanceOf(VectorLayer);
+    expect(result[2].getSourceState()).toBe('ready');
+  });
 });
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts b/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts
index c092a1465003e3c94414fd18582a6012dd74993a..950ae0ca14e9c581dd0016b2645bb71e0433c089 100644
--- a/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts
+++ b/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts
@@ -1,7 +1,8 @@
 /* eslint-disable no-magic-numbers */
 import { useEffect } from 'react';
 import { MapConfig, MapInstance } from '../../MapViewer.types';
-import { useOlMapPinsLayer } from './useOlMapPinsLayer';
+import { useOlMapPinsLayer } from './pinsLayer/useOlMapPinsLayer';
+import { useOlMapReactionsLayer } from './reactionsLayer/useOlMapReactionsLayer';
 import { useOlMapTileLayer } from './useOlMapTileLayer';
 
 interface UseOlMapLayersInput {
@@ -11,14 +12,15 @@ interface UseOlMapLayersInput {
 export const useOlMapLayers = ({ mapInstance }: UseOlMapLayersInput): MapConfig['layers'] => {
   const tileLayer = useOlMapTileLayer();
   const pinsLayer = useOlMapPinsLayer();
+  const reactionsLayer = useOlMapReactionsLayer();
 
   useEffect(() => {
     if (!mapInstance) {
       return;
     }
 
-    mapInstance.setLayers([tileLayer, pinsLayer]);
-  }, [tileLayer, pinsLayer, mapInstance]);
+    mapInstance.setLayers([tileLayer, reactionsLayer, pinsLayer]);
+  }, [reactionsLayer, tileLayer, pinsLayer, mapInstance]);
 
-  return [tileLayer, pinsLayer];
+  return [tileLayer, pinsLayer, reactionsLayer];
 };
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapPinsLayer.ts b/src/components/Map/MapViewer/utils/config/useOlMapPinsLayer.ts
deleted file mode 100644
index 3244cf3a75e75a2a03fb23fc8dedb7eb43677bbf..0000000000000000000000000000000000000000
--- a/src/components/Map/MapViewer/utils/config/useOlMapPinsLayer.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-/* eslint-disable no-magic-numbers */
-import { PIN_SIZE } from '@/constants/canvas';
-import { allBioEntitesSelectorOfCurrentMap } from '@/redux/bioEntity/bioEntity.selectors';
-import { BioEntity } from '@/types/models';
-import { UsePointToProjectionResult, usePointToProjection } from '@/utils/map/usePointToProjection';
-import { Feature } from 'ol';
-import { Point as OlPoint } from 'ol/geom';
-import BaseLayer from 'ol/layer/Base';
-import VectorLayer from 'ol/layer/Vector';
-import VectorSource from 'ol/source/Vector';
-import Icon from 'ol/style/Icon';
-import Style from 'ol/style/Style';
-import { useMemo } from 'react';
-import { useSelector } from 'react-redux';
-import { getCanvasIcon } from './getCanvasIcon';
-
-const getPinFeature = (
-  { x, y, width, height, name }: BioEntity,
-  pointToProjection: UsePointToProjectionResult,
-): Feature => {
-  const point = {
-    x: x + width / 2,
-    y: y + height / 2,
-  };
-
-  return new Feature({
-    geometry: new OlPoint(pointToProjection(point)),
-    name,
-  });
-};
-
-const getPinStyle = ({ value, color }: { value: number; color: string }): Style =>
-  new Style({
-    image: new Icon({
-      displacement: [0, PIN_SIZE.height],
-      anchorXUnits: 'fraction',
-      anchorYUnits: 'pixels',
-      img: getCanvasIcon({
-        color,
-        value,
-      }),
-    }),
-  });
-
-export const useOlMapPinsLayer = (): BaseLayer => {
-  const pointToProjection = usePointToProjection();
-  const bioEntites = useSelector(allBioEntitesSelectorOfCurrentMap);
-
-  const bioEntityFeatures = useMemo(
-    () =>
-      bioEntites.map(({ bioEntity }, index) => {
-        const feature = getPinFeature(bioEntity, pointToProjection);
-        const style = getPinStyle({
-          color: '#106AD7',
-          value: index + 1,
-        });
-
-        feature.setStyle(style);
-        return feature;
-      }),
-    [bioEntites, pointToProjection],
-  );
-
-  const vectorSource = useMemo(() => {
-    return new VectorSource({
-      features: [...bioEntityFeatures],
-    });
-  }, [bioEntityFeatures]);
-
-  const pinsLayer = useMemo(
-    () =>
-      new VectorLayer({
-        source: vectorSource,
-      }),
-    [vectorSource],
-  );
-
-  return pinsLayer;
-};
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/getSearchResults.test.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/getSearchResults.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5533b62d166c032bd0341524805b0dad29836c8c
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/getSearchResults.test.ts
@@ -0,0 +1,102 @@
+/* eslint-disable no-magic-numbers */
+import {
+  ELEMENT_SEARCH_RESULT_MOCK_ALIAS,
+  ELEMENT_SEARCH_RESULT_MOCK_REACTION,
+} from '@/models/mocks/elementSearchResultMock';
+import { apiPath } from '@/redux/apiPath';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { HttpStatusCode } from 'axios';
+import { getSearchResults } from './getSearchResults';
+
+const mockedAxiosOldClient = mockNetworkResponse();
+
+describe('getSearchResults - util', () => {
+  describe('when results type is ALIAS', () => {
+    const { modelId } = ELEMENT_SEARCH_RESULT_MOCK_ALIAS;
+    const mapSize = {
+      width: 270,
+      height: 270,
+      tileSize: 256,
+      minZoom: 2,
+      maxZoom: 9,
+    };
+    const coordinate = [270, 270];
+    const point = { x: 540.0072763538013, y: 539.9927236461986 };
+
+    beforeAll(() => {
+      mockedAxiosOldClient
+        .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
+        .reply(HttpStatusCode.Ok, [ELEMENT_SEARCH_RESULT_MOCK_ALIAS]);
+    });
+
+    it('returns valid array of objects', async () => {
+      const result = await getSearchResults({
+        coordinate,
+        mapSize,
+        modelId,
+      });
+
+      expect(result).toEqual([ELEMENT_SEARCH_RESULT_MOCK_ALIAS]);
+    });
+  });
+
+  describe('when results type is REACTION', () => {
+    const { modelId } = ELEMENT_SEARCH_RESULT_MOCK_REACTION;
+    const mapSize = {
+      width: 270,
+      height: 270,
+      tileSize: 256,
+      minZoom: 2,
+      maxZoom: 9,
+    };
+    const coordinate = [270, 270];
+    const point = { x: 540.0072763538013, y: 539.9927236461986 };
+
+    beforeAll(() => {
+      mockedAxiosOldClient
+        .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
+        .reply(HttpStatusCode.Ok, [ELEMENT_SEARCH_RESULT_MOCK_REACTION]);
+    });
+
+    it('returns valid array of objects', async () => {
+      const result = await getSearchResults({
+        coordinate,
+        mapSize,
+        modelId,
+      });
+
+      expect(result).toEqual([ELEMENT_SEARCH_RESULT_MOCK_REACTION]);
+    });
+  });
+
+  describe('when results type is invalid', () => {
+    const { modelId } = ELEMENT_SEARCH_RESULT_MOCK_ALIAS;
+    const mapSize = {
+      width: 270,
+      height: 270,
+      tileSize: 256,
+      minZoom: 2,
+      maxZoom: 9,
+    };
+    const coordinate = [270, 270];
+    const point = { x: 540.0072763538013, y: 539.9927236461986 };
+
+    beforeAll(() => {
+      mockedAxiosOldClient
+        .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
+        .reply(HttpStatusCode.Ok, {
+          invalidObject: true,
+        });
+    });
+
+    it('should return undefined', async () => {
+      const result = await getSearchResults({
+        coordinate,
+        mapSize,
+        modelId,
+      });
+
+      expect(result).toEqual(undefined);
+    });
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/getSearchResults.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/getSearchResults.ts
new file mode 100644
index 0000000000000000000000000000000000000000..df376d4a846df12e4fa6820e893ca9e3b7773b3e
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/getSearchResults.ts
@@ -0,0 +1,22 @@
+import { MapSize } from '@/redux/map/map.types';
+import { ElementSearchResult } from '@/types/models';
+import { latLngToPoint } from '@/utils/map/latLngToPoint';
+import { getElementsByPoint } from '@/utils/search/getElementsByCoordinates';
+import { Coordinate } from 'ol/coordinate';
+import { toLonLat } from 'ol/proj';
+
+interface GetSearchResultsInput {
+  coordinate: Coordinate;
+  mapSize: MapSize;
+  modelId: number;
+}
+
+export const getSearchResults = async ({
+  coordinate,
+  mapSize,
+  modelId,
+}: GetSearchResultsInput): Promise<ElementSearchResult[] | undefined> => {
+  const [lng, lat] = toLonLat(coordinate);
+  const point = latLngToPoint([lat, lng], mapSize);
+  return getElementsByPoint({ point, currentModelId: modelId });
+};
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.test.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..701539ac758b99655a2537758fc04bca64f2f4c3
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.test.ts
@@ -0,0 +1,37 @@
+import { FIRST, SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
+import { bioEntityResponseFixture } from '@/models/fixtures/bioEntityContentsFixture';
+import { ELEMENT_SEARCH_RESULT_MOCK_ALIAS } from '@/models/mocks/elementSearchResultMock';
+import { apiPath } from '@/redux/apiPath';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { waitFor } from '@testing-library/react';
+import { HttpStatusCode } from 'axios';
+import { handleAliasResults } from './handleAliasResults';
+
+const mockedAxiosOldClient = mockNetworkResponse();
+
+describe('handleAliasResults - util', () => {
+  const { store } = getReduxStoreWithActionsListener();
+  const { dispatch } = store;
+
+  mockedAxiosOldClient
+    .onGet(
+      apiPath.getBioEntityContentsStringWithQuery({
+        searchQuery: ELEMENT_SEARCH_RESULT_MOCK_ALIAS.id.toString(),
+        isPerfectMatch: true,
+      }),
+    )
+    .reply(HttpStatusCode.Ok, bioEntityResponseFixture);
+
+  beforeAll(async () => {
+    handleAliasResults(dispatch)(ELEMENT_SEARCH_RESULT_MOCK_ALIAS);
+  });
+
+  it('should run getBioEntityAction', async () => {
+    await waitFor(() => {
+      const actions = store.getActions();
+      expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
+      expect(actions[FIRST].type).toEqual('project/getMultiBioEntity/pending');
+    });
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.ts
new file mode 100644
index 0000000000000000000000000000000000000000..024f627edf2bd8f150a2bb19e738005a433917e3
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.ts
@@ -0,0 +1,15 @@
+import { getMultiBioEntity } from '@/redux/bioEntity/bioEntity.thunks';
+import { AppDispatch } from '@/redux/store';
+import { ElementSearchResult } from '@/types/models';
+
+/* prettier-ignore */
+export const handleAliasResults =
+  (dispatch: AppDispatch) =>
+    async ({ id }: ElementSearchResult): Promise<void> => {
+      dispatch(
+        getMultiBioEntity({
+          searchQueries: [id.toString()],
+          isPerfectMatch: true
+        }),
+      );
+    };
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.test.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f188b5fc5828b89f43f98e6f590a05da7c66bbbd
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.test.ts
@@ -0,0 +1,15 @@
+import { FIRST } from '@/constants/common';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { handleDataReset } from './handleDataReset';
+
+describe('handleDataReset', () => {
+  const { store } = getReduxStoreWithActionsListener();
+  const { dispatch } = store;
+
+  it('should dispatch resetReactionsData action', () => {
+    dispatch(handleDataReset);
+
+    const actions = store.getActions();
+    expect(actions[FIRST].type).toBe('reactions/resetReactionsData');
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4d3e1d6d526ee22725aff6b92ccbf273eec5ff79
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.ts
@@ -0,0 +1,6 @@
+import { resetReactionsData } from '@/redux/reactions/reactions.slice';
+import { AppDispatch } from '@/redux/store';
+
+export const handleDataReset = (dispatch: AppDispatch): void => {
+  dispatch(resetReactionsData());
+};
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleReactionResults.test.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleReactionResults.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..21c6524d2eb8656cf19a870edb07e15d06963d6e
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleReactionResults.test.ts
@@ -0,0 +1,57 @@
+/* eslint-disable no-magic-numbers */
+import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
+import { bioEntityResponseFixture } from '@/models/fixtures/bioEntityContentsFixture';
+import { reactionsFixture } from '@/models/fixtures/reactionFixture';
+import {
+  ELEMENT_SEARCH_RESULT_MOCK_ALIAS,
+  ELEMENT_SEARCH_RESULT_MOCK_REACTION,
+} from '@/models/mocks/elementSearchResultMock';
+import { apiPath } from '@/redux/apiPath';
+import { mockNetworkNewAPIResponse, mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { HttpStatusCode } from 'axios';
+import { handleReactionResults } from './handleReactionResults';
+
+const mockedAxiosOldClient = mockNetworkResponse();
+const mockedAxiosNewClient = mockNetworkNewAPIResponse();
+
+describe('handleReactionResults - util', () => {
+  const { store } = getReduxStoreWithActionsListener();
+  const { dispatch } = store;
+
+  mockedAxiosNewClient
+    .onGet(
+      apiPath.getBioEntityContentsStringWithQuery({
+        searchQuery: ELEMENT_SEARCH_RESULT_MOCK_ALIAS.id.toString(),
+        isPerfectMatch: true,
+      }),
+    )
+    .reply(HttpStatusCode.Ok, bioEntityResponseFixture);
+
+  mockedAxiosOldClient
+    .onGet(apiPath.getReactionsWithIds([ELEMENT_SEARCH_RESULT_MOCK_REACTION.id]))
+    .reply(HttpStatusCode.Ok, reactionsFixture);
+
+  beforeAll(async () => {
+    handleReactionResults(dispatch)(ELEMENT_SEARCH_RESULT_MOCK_REACTION);
+  });
+
+  it('should run getReactionsByIds as first action', () => {
+    const actions = store.getActions();
+    expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
+    expect(actions[0].type).toEqual('reactions/getByIds/pending');
+    expect(actions[1].type).toEqual('reactions/getByIds/fulfilled');
+  });
+
+  it('should run setBioEntityContent to empty array as second action', () => {
+    const actions = store.getActions();
+    expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
+    expect(actions[2].type).toEqual('project/getMultiBioEntity/pending');
+  });
+
+  it('should run getBioEntity as third action', () => {
+    const actions = store.getActions();
+    expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
+    expect(actions[3].type).toEqual('project/getBioEntityContents/pending');
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleReactionResults.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleReactionResults.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5c5ae1a20eada4b0349d1b2972059cdb04265d69
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleReactionResults.ts
@@ -0,0 +1,30 @@
+import { FIRST, SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
+import { getMultiBioEntity } from '@/redux/bioEntity/bioEntity.thunks';
+import { getReactionsByIds } from '@/redux/reactions/reactions.thunks';
+import { AppDispatch } from '@/redux/store';
+import { ElementSearchResult, Reaction } from '@/types/models';
+import { PayloadAction } from '@reduxjs/toolkit';
+
+/* prettier-ignore */
+export const handleReactionResults =
+  (dispatch: AppDispatch) =>
+    async ({ id }: ElementSearchResult): Promise<void> => {
+      const data = await dispatch(getReactionsByIds([id])) as PayloadAction<Reaction[] | undefined>;
+      const payload = data?.payload;
+      if (!data || !payload || payload.length === SIZE_OF_EMPTY_ARRAY) {
+        return;
+      }
+
+      const { products, reactants, modifiers } = payload[FIRST];
+      const productsIds = products.map(p => p.aliasId);
+      const reactantsIds = reactants.map(r => r.aliasId);
+      const modifiersIds = modifiers.map(m => m.aliasId);
+      const bioEntitiesIds = [...productsIds, ...reactantsIds, ...modifiersIds].map(identifier => String(identifier));
+
+      await dispatch(
+        getMultiBioEntity({
+          searchQueries: bioEntitiesIds,
+          isPerfectMatch: true },
+        ),
+      );
+    };
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleSearchResultAction.test.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleSearchResultAction.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8492539613ec74eec4792b914632d354d64733cb
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleSearchResultAction.test.ts
@@ -0,0 +1,46 @@
+import {
+  ELEMENT_SEARCH_RESULT_MOCK_ALIAS,
+  ELEMENT_SEARCH_RESULT_MOCK_REACTION,
+} from '@/models/mocks/elementSearchResultMock';
+import * as handleAliasResults from './handleAliasResults';
+import * as handleReactionResults from './handleReactionResults';
+import { handleSearchResultAction } from './handleSearchResultAction';
+
+jest.mock('./handleAliasResults', () => ({
+  __esModule: true,
+  handleAliasResults: jest.fn().mockImplementation(() => (): null => null),
+}));
+
+jest.mock('./handleReactionResults', () => ({
+  __esModule: true,
+  handleReactionResults: jest.fn().mockImplementation(() => (): null => null),
+}));
+
+const handleAliasResultsSpy = jest.spyOn(handleAliasResults, 'handleAliasResults');
+const handleReactionResultsSpy = jest.spyOn(handleReactionResults, 'handleReactionResults');
+
+describe('handleSearchResultAction - util', () => {
+  const dispatch = jest.fn();
+
+  beforeEach(() => {
+    jest.clearAllMocks();
+  });
+
+  describe('on ALIAS search results', () => {
+    const searchResults = [ELEMENT_SEARCH_RESULT_MOCK_ALIAS];
+
+    it('should fire handleAliasResults', async () => {
+      await handleSearchResultAction({ searchResults, dispatch });
+      expect(handleAliasResultsSpy).toBeCalled();
+    });
+  });
+
+  describe('on REACTION search results', () => {
+    const searchResults = [ELEMENT_SEARCH_RESULT_MOCK_REACTION];
+
+    it('should fire handleReactionResults', async () => {
+      await handleSearchResultAction({ searchResults, dispatch });
+      expect(handleReactionResultsSpy).toBeCalled();
+    });
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleSearchResultAction.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleSearchResultAction.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e60af27ce2a06b6db202af658868857d57b341a7
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleSearchResultAction.ts
@@ -0,0 +1,24 @@
+import { FIRST } from '@/constants/common';
+import { AppDispatch } from '@/redux/store';
+import { ElementSearchResult } from '@/types/models';
+import { handleAliasResults } from './handleAliasResults';
+import { handleReactionResults } from './handleReactionResults';
+
+interface HandleSearchResultActionInput {
+  searchResults: ElementSearchResult[];
+  dispatch: AppDispatch;
+}
+
+export const handleSearchResultAction = async ({
+  searchResults,
+  dispatch,
+}: HandleSearchResultActionInput): Promise<void> => {
+  const closestSearchResult = searchResults[FIRST];
+  const { type } = closestSearchResult;
+  const action = {
+    ALIAS: handleAliasResults,
+    REACTION: handleReactionResults,
+  }[type];
+
+  await action(dispatch)(closestSearchResult);
+};
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/onMapSingleClick.test.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/onMapSingleClick.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..806d2a7ca5638841276a7fb90c6ae2b692bc0648
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/onMapSingleClick.test.ts
@@ -0,0 +1,175 @@
+/* eslint-disable no-magic-numbers */
+import {
+  ELEMENT_SEARCH_RESULT_MOCK_ALIAS,
+  ELEMENT_SEARCH_RESULT_MOCK_REACTION,
+} from '@/models/mocks/elementSearchResultMock';
+import { apiPath } from '@/redux/apiPath';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { waitFor } from '@testing-library/react';
+import { HttpStatusCode } from 'axios';
+import { MapBrowserEvent } from 'ol';
+import * as handleDataReset from './handleDataReset';
+import * as handleSearchResultAction from './handleSearchResultAction';
+import { onMapSingleClick } from './onMapSingleClick';
+
+jest.mock('./handleSearchResultAction', () => ({
+  __esModule: true,
+  ...jest.requireActual('./handleSearchResultAction'),
+}));
+jest.mock('./handleDataReset', () => ({
+  __esModule: true,
+  ...jest.requireActual('./handleDataReset'),
+}));
+
+const mockedAxiosOldClient = mockNetworkResponse();
+
+const handleSearchResultActionSpy = jest.spyOn(
+  handleSearchResultAction,
+  'handleSearchResultAction',
+);
+const handleDataResetSpy = jest.spyOn(handleDataReset, 'handleDataReset');
+
+const getEvent = (coordinate: MapBrowserEvent<UIEvent>['coordinate']): MapBrowserEvent<UIEvent> =>
+  ({
+    coordinate,
+  }) as unknown as MapBrowserEvent<UIEvent>;
+
+describe('onMapSingleClick - util', () => {
+  beforeEach(() => {
+    jest.clearAllMocks();
+    jest.resetAllMocks();
+  });
+
+  describe('when always', () => {
+    const { store } = getReduxStoreWithActionsListener();
+    const { dispatch } = store;
+    const modelId = 1000;
+    const mapSize = {
+      width: 90,
+      height: 90,
+      tileSize: 256,
+      minZoom: 2,
+      maxZoom: 9,
+    };
+    const handler = onMapSingleClick(mapSize, modelId, dispatch);
+    const coordinate = [90, 90];
+    const event = getEvent(coordinate);
+
+    it('should fire data reset handler', async () => {
+      await handler(event);
+      expect(handleDataResetSpy).toBeCalled();
+    });
+  });
+
+  describe('when searchResults are undefined', () => {
+    const { store } = getReduxStoreWithActionsListener();
+    const { dispatch } = store;
+    const modelId = 1000;
+    const mapSize = {
+      width: 90,
+      height: 90,
+      tileSize: 256,
+      minZoom: 2,
+      maxZoom: 9,
+    };
+    const handler = onMapSingleClick(mapSize, modelId, dispatch);
+    const coordinate = [90, 90];
+    const point = { x: 180.0008084837557, y: 179.99919151624428 };
+    const event = getEvent(coordinate);
+
+    mockedAxiosOldClient
+      .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
+      .reply(HttpStatusCode.Ok, undefined);
+
+    it('does not fire search result action', async () => {
+      await handler(event);
+      expect(handleSearchResultActionSpy).not.toBeCalled();
+    });
+  });
+
+  describe('when searchResults are empty', () => {
+    const { store } = getReduxStoreWithActionsListener();
+    const { dispatch } = store;
+
+    const modelId = 1000;
+    const mapSize = {
+      width: 180,
+      height: 180,
+      tileSize: 256,
+      minZoom: 2,
+      maxZoom: 9,
+    };
+
+    const handler = onMapSingleClick(mapSize, modelId, dispatch);
+    const coordinate = [180, 180];
+    const point = { x: 360.0032339350228, y: 359.9967660649771 };
+    const event = getEvent(coordinate);
+
+    mockedAxiosOldClient
+      .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
+      .reply(HttpStatusCode.Ok, []);
+
+    it('does not fire search result action', async () => {
+      await handler(event);
+      expect(handleSearchResultActionSpy).not.toBeCalled();
+    });
+  });
+
+  describe('when searchResults are valid', () => {
+    describe('when results type is ALIAS', () => {
+      const { store } = getReduxStoreWithActionsListener();
+      const { dispatch } = store;
+      const { modelId } = ELEMENT_SEARCH_RESULT_MOCK_ALIAS;
+      const mapSize = {
+        width: 270,
+        height: 270,
+        tileSize: 256,
+        minZoom: 2,
+        maxZoom: 9,
+      };
+      const coordinate = [270, 270];
+      const point = { x: 540.0072763538013, y: 539.9927236461986 };
+      const event = getEvent(coordinate);
+
+      mockedAxiosOldClient
+        .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
+        .reply(HttpStatusCode.Ok, [ELEMENT_SEARCH_RESULT_MOCK_ALIAS]);
+
+      it('does fire search result action handler', async () => {
+        const handler = onMapSingleClick(mapSize, modelId, dispatch);
+        await handler(event);
+        await waitFor(() => expect(handleSearchResultActionSpy).toBeCalled());
+      });
+    });
+
+    describe('when results type is REACTION', () => {
+      const { store } = getReduxStoreWithActionsListener();
+      const { dispatch } = store;
+      const { modelId } = ELEMENT_SEARCH_RESULT_MOCK_REACTION;
+      const mapSize = {
+        width: 0,
+        height: 0,
+        tileSize: 256,
+        minZoom: 2,
+        maxZoom: 9,
+      };
+      const coordinate = [0, 0];
+      const point = {
+        x: 0,
+        y: 0,
+      };
+      const event = getEvent(coordinate);
+
+      mockedAxiosOldClient
+        .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
+        .reply(HttpStatusCode.Ok, [ELEMENT_SEARCH_RESULT_MOCK_REACTION]);
+
+      it('does fire search result action - handle reaction', async () => {
+        const handler = onMapSingleClick(mapSize, modelId, dispatch);
+        await handler(event);
+        await waitFor(() => expect(handleSearchResultActionSpy).toBeCalled());
+      });
+    });
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/onMapSingleClick.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/onMapSingleClick.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cdd4abbf45f1025b0695c3c40dfb141348fdccbf
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/onMapSingleClick.ts
@@ -0,0 +1,21 @@
+import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
+import { MapSize } from '@/redux/map/map.types';
+import { AppDispatch } from '@/redux/store';
+import { MapBrowserEvent } from 'ol';
+import { getSearchResults } from './getSearchResults';
+import { handleDataReset } from './handleDataReset';
+import { handleSearchResultAction } from './handleSearchResultAction';
+
+/* prettier-ignore */
+export const onMapSingleClick =
+  (mapSize: MapSize, modelId: number, dispatch: AppDispatch) =>
+    async ({ coordinate }: MapBrowserEvent<UIEvent>): Promise<void> => {
+      dispatch(handleDataReset);
+
+      const searchResults = await getSearchResults({ coordinate, mapSize, modelId });
+      if (!searchResults || searchResults.length === SIZE_OF_EMPTY_ARRAY) {
+        return;
+      }
+
+      handleSearchResultAction({ searchResults, dispatch });
+    };
diff --git a/src/components/Map/MapViewer/utils/listeners/onMapSingleClick.test.ts b/src/components/Map/MapViewer/utils/listeners/onMapSingleClick.test.ts
deleted file mode 100644
index ac9007988cf2707be414031310258426ec1f4230..0000000000000000000000000000000000000000
--- a/src/components/Map/MapViewer/utils/listeners/onMapSingleClick.test.ts
+++ /dev/null
@@ -1,234 +0,0 @@
-/* eslint-disable no-magic-numbers */
-import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
-import { bioEntityResponseFixture } from '@/models/fixtures/bioEntityContentsFixture';
-import { reactionsFixture } from '@/models/fixtures/reactionFixture';
-import {
-  ELEMENT_SEARCH_RESULT_MOCK_ALIAS,
-  ELEMENT_SEARCH_RESULT_MOCK_REACTION,
-} from '@/models/mocks/elementSearchResultMock';
-import { apiPath } from '@/redux/apiPath';
-import { mockNetworkNewAPIResponse, mockNetworkResponse } from '@/utils/mockNetworkResponse';
-import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
-import { waitFor } from '@testing-library/react';
-import { HttpStatusCode } from 'axios';
-import { MapBrowserEvent } from 'ol';
-import * as onMapSingleClickUtils from './onMapSingleClick';
-import { handleAliasResults, handleReactionResults } from './onMapSingleClick';
-
-const { onMapSingleClick } = onMapSingleClickUtils;
-const mockedAxiosOldClient = mockNetworkResponse();
-const mockedAxiosNewClient = mockNetworkNewAPIResponse();
-
-const getEvent = (coordinate: MapBrowserEvent<UIEvent>['coordinate']): MapBrowserEvent<UIEvent> =>
-  ({
-    coordinate,
-  }) as unknown as MapBrowserEvent<UIEvent>;
-
-describe('onMapSingleClick - util', () => {
-  beforeEach(() => {
-    jest.clearAllMocks();
-    jest.resetAllMocks();
-  });
-
-  describe('when searchResults are undefined', () => {
-    const { store } = getReduxStoreWithActionsListener();
-    const { dispatch } = store;
-    const modelId = 1000;
-    const mapSize = {
-      width: 90,
-      height: 90,
-      tileSize: 256,
-      minZoom: 2,
-      maxZoom: 9,
-    };
-    const handler = onMapSingleClick(mapSize, modelId, dispatch);
-    const coordinate = [90, 90];
-    const point = { x: 180.0008084837557, y: 179.99919151624428 };
-    const event = getEvent(coordinate);
-
-    mockedAxiosOldClient
-      .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
-      .reply(HttpStatusCode.Ok, undefined);
-
-    it('does not fire search result action', async () => {
-      await handler(event);
-      const actions = store.getActions();
-      expect(actions.length).toBe(SIZE_OF_EMPTY_ARRAY);
-    });
-  });
-
-  describe('when searchResults are empty', () => {
-    const { store } = getReduxStoreWithActionsListener();
-    const { dispatch } = store;
-
-    const modelId = 1000;
-    const mapSize = {
-      width: 180,
-      height: 180,
-      tileSize: 256,
-      minZoom: 2,
-      maxZoom: 9,
-    };
-
-    const handler = onMapSingleClick(mapSize, modelId, dispatch);
-    const coordinate = [180, 180];
-    const point = { x: 360.0032339350228, y: 359.9967660649771 };
-    const event = getEvent(coordinate);
-
-    mockedAxiosOldClient
-      .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
-      .reply(HttpStatusCode.Ok, []);
-
-    it('does not fire search result action', async () => {
-      await handler(event);
-      const actions = store.getActions();
-      expect(actions.length).toBe(SIZE_OF_EMPTY_ARRAY);
-    });
-  });
-
-  describe('when searchResults are valid', () => {
-    describe('when results type is ALIAS', () => {
-      const { store } = getReduxStoreWithActionsListener();
-      const { dispatch } = store;
-      const { modelId } = ELEMENT_SEARCH_RESULT_MOCK_ALIAS;
-      const mapSize = {
-        width: 270,
-        height: 270,
-        tileSize: 256,
-        minZoom: 2,
-        maxZoom: 9,
-      };
-      const coordinate = [270, 270];
-      const point = { x: 540.0072763538013, y: 539.9927236461986 };
-      const event = getEvent(coordinate);
-
-      mockedAxiosOldClient
-        .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
-        .reply(HttpStatusCode.Ok, [ELEMENT_SEARCH_RESULT_MOCK_ALIAS]);
-
-      beforeAll(async () => {
-        const handler = onMapSingleClick(mapSize, modelId, dispatch);
-        await handler(event);
-      });
-
-      it('does fire search result action - getBioEntity', async () => {
-        const actions = store.getActions();
-        expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
-        expect(actions[0].type).toEqual('project/getMultiBioEntity/pending');
-      });
-
-      it('does NOT fire search result action - getReactionsByIds', async () => {
-        const actions = store.getActions();
-        expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
-        expect(actions[0].type).not.toEqual('reactions/getByIds/pending');
-      });
-    });
-
-    describe('when results type is REACTION', () => {
-      const { store } = getReduxStoreWithActionsListener();
-      const { dispatch } = store;
-      const { modelId } = ELEMENT_SEARCH_RESULT_MOCK_REACTION;
-      const mapSize = {
-        width: 0,
-        height: 0,
-        tileSize: 256,
-        minZoom: 2,
-        maxZoom: 9,
-      };
-      const coordinate = [0, 0];
-      const point = {
-        x: 0,
-        y: 0,
-      };
-      const event = getEvent(coordinate);
-
-      mockedAxiosOldClient
-        .onGet(apiPath.getSingleBioEntityContentsStringWithCoordinates(point, modelId))
-        .reply(HttpStatusCode.Ok, [ELEMENT_SEARCH_RESULT_MOCK_REACTION]);
-
-      beforeAll(async () => {
-        const handler = onMapSingleClick(mapSize, modelId, dispatch);
-        await handler(event);
-      });
-
-      it('does NOT fire search result action - getBioEntity', async () => {
-        const actions = store.getActions();
-        expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
-        expect(actions[0].type).not.toEqual('project/getBioEntityContents/pending');
-      });
-
-      it('does fire search result action - getReactionsByIds', async () => {
-        const actions = store.getActions();
-        expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
-        expect(actions[0].type).toEqual('reactions/getByIds/pending');
-      });
-    });
-  });
-});
-
-describe('handleAliasResults - util', () => {
-  const { store } = getReduxStoreWithActionsListener();
-  const { dispatch } = store;
-
-  mockedAxiosOldClient
-    .onGet(
-      apiPath.getBioEntityContentsStringWithQuery({
-        searchQuery: ELEMENT_SEARCH_RESULT_MOCK_ALIAS.id.toString(),
-        isPerfectMatch: true,
-      }),
-    )
-    .reply(HttpStatusCode.Ok, bioEntityResponseFixture);
-
-  beforeAll(async () => {
-    handleAliasResults(dispatch)(ELEMENT_SEARCH_RESULT_MOCK_ALIAS);
-  });
-
-  it('should run getBioEntityAction', async () => {
-    await waitFor(() => {
-      const actions = store.getActions();
-      expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
-      expect(actions[0].type).toEqual('project/getMultiBioEntity/pending');
-    });
-  });
-});
-
-describe('handleReactionResults - util', () => {
-  const { store } = getReduxStoreWithActionsListener();
-  const { dispatch } = store;
-
-  mockedAxiosNewClient
-    .onGet(
-      apiPath.getBioEntityContentsStringWithQuery({
-        searchQuery: ELEMENT_SEARCH_RESULT_MOCK_ALIAS.id.toString(),
-        isPerfectMatch: true,
-      }),
-    )
-    .reply(HttpStatusCode.Ok, bioEntityResponseFixture);
-
-  mockedAxiosOldClient
-    .onGet(apiPath.getReactionsWithIds([ELEMENT_SEARCH_RESULT_MOCK_REACTION.id]))
-    .reply(HttpStatusCode.Ok, reactionsFixture);
-
-  beforeAll(async () => {
-    handleReactionResults(dispatch)(ELEMENT_SEARCH_RESULT_MOCK_REACTION);
-  });
-
-  it('should run getReactionsByIds as first action', () => {
-    const actions = store.getActions();
-    expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
-    expect(actions[0].type).toEqual('reactions/getByIds/pending');
-    expect(actions[1].type).toEqual('reactions/getByIds/fulfilled');
-  });
-
-  it('should run setBioEntityContent to empty array as second action', () => {
-    const actions = store.getActions();
-    expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
-    expect(actions[2].type).toEqual('project/getMultiBioEntity/pending');
-  });
-
-  it('should run getBioEntity as third action', () => {
-    const actions = store.getActions();
-    expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
-    expect(actions[3].type).toEqual('project/getBioEntityContents/pending');
-  });
-});
diff --git a/src/components/Map/MapViewer/utils/listeners/onMapSingleClick.ts b/src/components/Map/MapViewer/utils/listeners/onMapSingleClick.ts
deleted file mode 100644
index 368c42414cfdc80d64f7ba8de84d1b32ab74c0e0..0000000000000000000000000000000000000000
--- a/src/components/Map/MapViewer/utils/listeners/onMapSingleClick.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
-import { getMultiBioEntity } from '@/redux/bioEntity/bioEntity.thunks';
-import { MapSize } from '@/redux/map/map.types';
-import { AppDispatch } from '@/redux/store';
-import { ElementSearchResult, Reaction } from '@/types/models';
-import { latLngToPoint } from '@/utils/map/latLngToPoint';
-import { getElementsByPoint } from '@/utils/search/getElementsByCoordinates';
-import { PayloadAction } from '@reduxjs/toolkit';
-import { MapBrowserEvent } from 'ol';
-import { toLonLat } from 'ol/proj';
-import { getReactionsByIds } from '../../../../../redux/reactions/reactions.thunks';
-
-const FIRST = 0;
-
-/* prettier-ignore */
-export const handleAliasResults =
-  (dispatch: AppDispatch) =>
-    async ({ id }: ElementSearchResult): Promise<void> => {
-      dispatch(
-        getMultiBioEntity({
-          searchQueries: [id.toString()],
-          isPerfectMatch: true
-        }),
-      );
-    };
-
-/* prettier-ignore */
-export const handleReactionResults =
-  (dispatch: AppDispatch) =>
-    async ({ id }: ElementSearchResult): Promise<void> => {
-      const data = await dispatch(getReactionsByIds([id])) as PayloadAction<Reaction[] | undefined>;
-      const payload = data?.payload;
-      if (!data || !payload || payload.length === SIZE_OF_EMPTY_ARRAY) {
-        return;
-      }
-
-      const { products, reactants, modifiers } = payload[FIRST];
-      const productsIds = products.map(p => p.aliasId);
-      const reactantsIds = reactants.map(r => r.aliasId);
-      const modifiersIds = modifiers.map(m => m.aliasId);
-      const bioEntitiesIds = [...productsIds, ...reactantsIds, ...modifiersIds].map(identifier => String(identifier));
-
-      await dispatch(
-        getMultiBioEntity({
-          searchQueries: bioEntitiesIds,
-          isPerfectMatch: true },
-        ),
-      );
-    };
-
-/* prettier-ignore */
-export const onMapSingleClick =
-  (mapSize: MapSize, modelId: number, dispatch: AppDispatch) =>
-    async (e: MapBrowserEvent<UIEvent>): Promise<void> => {
-      const [lng, lat] = toLonLat(e.coordinate);
-      const point = latLngToPoint([lat, lng], mapSize);
-      const searchResults = await getElementsByPoint({ point, currentModelId: modelId });
-
-      if (!searchResults || searchResults.length === SIZE_OF_EMPTY_ARRAY) {
-        return;
-      }
-
-      const closestSearchResult = searchResults[FIRST];
-      const { type } = closestSearchResult;
-      const action = {
-        'ALIAS': handleAliasResults,
-        'REACTION': handleReactionResults,
-      }[type];
-
-      await action(dispatch)(closestSearchResult);
-    };
diff --git a/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.test.ts b/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.test.ts
index 0f409f880c75c18fccfda813288283c40598b89f..68b1c28b94dcdaef277951c2f726be845a6c61df 100644
--- a/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.test.ts
+++ b/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.test.ts
@@ -3,8 +3,8 @@ import mapSlice from '@/redux/map/map.slice';
 import { getReduxWrapperUsingSliceReducer } from '@/utils/testing/getReduxWrapperUsingSliceReducer';
 import { renderHook } from '@testing-library/react';
 import { View } from 'ol';
+import * as singleClickListener from './mapSingleClick/onMapSingleClick';
 import * as positionListener from './onMapPositionChange';
-import * as singleClickListener from './onMapSingleClick';
 import { useOlMapListeners } from './useOlMapListeners';
 
 jest.mock('./onMapPositionChange', () => ({
@@ -12,7 +12,7 @@ jest.mock('./onMapPositionChange', () => ({
   onMapPositionChange: jest.fn(),
 }));
 
-jest.mock('./onMapSingleClick', () => ({
+jest.mock('./mapSingleClick/onMapSingleClick', () => ({
   __esModule: true,
   onMapSingleClick: jest.fn(),
 }));
diff --git a/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts b/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts
index 5cad414f88a9fa979d8e31d3dce15301add65831..efab477c9004c4a64600f3c6df52d1e7487a2d1d 100644
--- a/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts
+++ b/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts
@@ -8,8 +8,8 @@ import { useEffect } from 'react';
 import { useSelector } from 'react-redux';
 import { useDebouncedCallback } from 'use-debounce';
 import { MapInstance } from '../../MapViewer.types';
+import { onMapSingleClick } from './mapSingleClick/onMapSingleClick';
 import { onMapPositionChange } from './onMapPositionChange';
-import { onMapSingleClick } from './onMapSingleClick';
 
 interface UseOlMapListenersInput {
   view: View;
diff --git a/src/constants/canvas.ts b/src/constants/canvas.ts
index b9741f3001cb3defe3931b799a208860b4110879..31b30eb16de6358c622dcbb10f395bba7fb9556d 100644
--- a/src/constants/canvas.ts
+++ b/src/constants/canvas.ts
@@ -1,3 +1,5 @@
+import { PinType } from '@/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types';
+
 export const PIN_PATH2D =
   'M12.3077 0C6.25641 0 0 4.61538 0 12.3077C0 19.5897 11.0769 30.9744 11.5897 31.4872C11.7949 31.6923 12 31.7949 12.3077 31.7949C12.6154 31.7949 12.8205 31.6923 13.0256 31.4872C13.5385 30.9744 24.6154 19.6923 24.6154 12.3077C24.6154 4.61538 18.359 0 12.3077 0Z';
 
@@ -5,3 +7,15 @@ export const PIN_SIZE = {
   width: 25,
   height: 32,
 };
+
+export const PINS_COLORS: Record<PinType, string> = {
+  drugs: '#F48C41',
+  chemicals: '#640CE3',
+  bioEntity: '#106AD7',
+  mirna: '#F1009F',
+  none: '#000',
+};
+
+export const LINE_COLOR = '#00AAFF';
+
+export const LINE_WIDTH = 6;
diff --git a/src/constants/common.ts b/src/constants/common.ts
index 2651c7063a81f9981f27c21bce15a092c7eb5fd1..1825686b98af79ba59146ff6c567b8a50170940e 100644
--- a/src/constants/common.ts
+++ b/src/constants/common.ts
@@ -1,2 +1,5 @@
 export const SIZE_OF_EMPTY_ARRAY = 0;
 export const ZERO = 0;
+export const FIRST = 0;
+
+export const ONE = 1;
diff --git a/src/redux/bioEntity/bioEntity.selectors.ts b/src/redux/bioEntity/bioEntity.selectors.ts
index bbf46eb1fa4380fc2d6338ada7aaacaf0be8014a..bcaeda20ef55efa082341b3d6600b688128f4f27 100644
--- a/src/redux/bioEntity/bioEntity.selectors.ts
+++ b/src/redux/bioEntity/bioEntity.selectors.ts
@@ -1,10 +1,11 @@
 import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
 import { rootSelector } from '@/redux/root/root.selectors';
-import { BioEntityContent } from '@/types/models';
-import { createSelector } from '@reduxjs/toolkit';
 import { MultiSearchData } from '@/types/fetchDataState';
-import { currentModelIdSelector, modelsDataSelector } from '../models/models.selectors';
+import { BioEntity, BioEntityContent } from '@/types/models';
+import { createSelector } from '@reduxjs/toolkit';
 import { currentSelectedSearchElement } from '../drawer/drawer.selectors';
+import { currentModelIdSelector, modelsDataSelector } from '../models/models.selectors';
+import { reduceToJoinedMultiSearchResult } from './bioEntity.utils';
 
 export const bioEntitySelector = createSelector(rootSelector, state => state.bioEntity);
 
@@ -22,15 +23,38 @@ export const loadingBioEntityStatusSelector = createSelector(
   state => state?.loading,
 );
 
-export const allBioEntitesSelectorOfCurrentMap = createSelector(
+export const bioEntitiesForSelectedSearchElementOrAllFallback = createSelector(
+  bioEntitySelector,
   bioEntitiesForSelectedSearchElement,
+  currentSelectedSearchElement,
+  (
+    bioEntitiesState,
+    bioEntitiesOfSelected,
+    currentSearchElement,
+  ): MultiSearchData<BioEntityContent[]> | undefined => {
+    if (!currentSearchElement) {
+      const bioEntitiesFiltered = bioEntitiesState.data.filter(d => d !== undefined);
+
+      return bioEntitiesFiltered.length === SIZE_OF_EMPTY_ARRAY
+        ? undefined
+        : bioEntitiesFiltered.reduce(reduceToJoinedMultiSearchResult);
+    }
+
+    return bioEntitiesOfSelected;
+  },
+);
+
+export const allBioEntitesSelectorOfCurrentMap = createSelector(
+  bioEntitiesForSelectedSearchElementOrAllFallback,
   currentModelIdSelector,
-  (bioEntities, currentModelId): BioEntityContent[] => {
+  (bioEntities, currentModelId): BioEntity[] => {
     if (!bioEntities) {
       return [];
     }
 
-    return (bioEntities?.data || []).filter(({ bioEntity }) => bioEntity.model === currentModelId);
+    return (bioEntities?.data || [])
+      .filter(({ bioEntity }) => bioEntity.model === currentModelId)
+      .map(({ bioEntity }) => bioEntity);
   },
 );
 
diff --git a/src/redux/bioEntity/bioEntity.utils.ts b/src/redux/bioEntity/bioEntity.utils.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8aa0c336e06f2fd827d7748b5403a1e5bf62ba1b
--- /dev/null
+++ b/src/redux/bioEntity/bioEntity.utils.ts
@@ -0,0 +1,14 @@
+import { MultiSearchData } from '@/types/fetchDataState';
+import { BioEntityContent } from '@/types/models';
+
+type MultiSearchBioEntityData = MultiSearchData<BioEntityContent[]>;
+type ToJoinedMultiSearchResultFun = (
+  a: MultiSearchBioEntityData,
+  b: MultiSearchBioEntityData,
+) => MultiSearchBioEntityData;
+
+export const reduceToJoinedMultiSearchResult: ToJoinedMultiSearchResultFun = (a, b) => ({
+  ...b,
+  searchQueryElement: `${a.searchQueryElement};${b.searchQueryElement}`,
+  data: (a.data || []).concat(b.data || []),
+});
diff --git a/src/redux/reactions/reactions.constants.ts b/src/redux/reactions/reactions.constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a7b9f099193540abc66d052d902faee2d5775c76
--- /dev/null
+++ b/src/redux/reactions/reactions.constants.ts
@@ -0,0 +1,7 @@
+import { ReactionsState } from './reactions.types';
+
+export const REACTIONS_INITIAL_STATE: ReactionsState = {
+  data: [],
+  loading: 'idle',
+  error: { name: '', message: '' },
+};
diff --git a/src/redux/reactions/reactions.reducers.ts b/src/redux/reactions/reactions.reducers.ts
index 8673c7a6182481e37fa9236a7b7c80e6f93b6ecf..92ecef9cf7d86e0830255a74b481772e085d52c1 100644
--- a/src/redux/reactions/reactions.reducers.ts
+++ b/src/redux/reactions/reactions.reducers.ts
@@ -1,4 +1,5 @@
 import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
+import { REACTIONS_INITIAL_STATE } from './reactions.constants';
 import { getReactionsByIds } from './reactions.thunks';
 import { ReactionsState } from './reactions.types';
 
@@ -15,3 +16,9 @@ export const getReactionsReducer = (builder: ActionReducerMapBuilder<ReactionsSt
     // TODO: error management to be discussed in the team
   });
 };
+
+export const resetReactionsDataReducer = (state: ReactionsState): void => {
+  state.data = REACTIONS_INITIAL_STATE.data;
+  state.error = REACTIONS_INITIAL_STATE.error;
+  state.loading = REACTIONS_INITIAL_STATE.loading;
+};
diff --git a/src/redux/reactions/reactions.selector.ts b/src/redux/reactions/reactions.selector.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1f907b39550b23aacbb831687631e8562eec6a50
--- /dev/null
+++ b/src/redux/reactions/reactions.selector.ts
@@ -0,0 +1,19 @@
+import { Reaction } from '@/types/models';
+import { createSelector } from '@reduxjs/toolkit';
+import { currentModelIdSelector } from '../models/models.selectors';
+import { rootSelector } from '../root/root.selectors';
+
+export const reactionsSelector = createSelector(rootSelector, state => state.reactions);
+
+export const reactionsDataSelector = createSelector(
+  reactionsSelector,
+  reactions => reactions?.data || [],
+);
+
+export const allReactionsSelectorOfCurrentMap = createSelector(
+  reactionsDataSelector,
+  currentModelIdSelector,
+  (reactions, currentModelId): Reaction[] => {
+    return reactions.filter(({ modelId }) => modelId === currentModelId);
+  },
+);
diff --git a/src/redux/reactions/reactions.slice.ts b/src/redux/reactions/reactions.slice.ts
index 47eeea91d64d513ba3e6fe8ac5f5890a67baaa88..f97e9050155d87e496cb8adada0f8e28f0d0f4ba 100644
--- a/src/redux/reactions/reactions.slice.ts
+++ b/src/redux/reactions/reactions.slice.ts
@@ -1,20 +1,18 @@
 import { createSlice } from '@reduxjs/toolkit';
-import { getReactionsReducer } from './reactions.reducers';
-import { ReactionsState } from './reactions.types';
-
-const initialState: ReactionsState = {
-  data: [],
-  loading: 'idle',
-  error: { name: '', message: '' },
-};
+import { REACTIONS_INITIAL_STATE } from './reactions.constants';
+import { getReactionsReducer, resetReactionsDataReducer } from './reactions.reducers';
 
 export const reactionsSlice = createSlice({
   name: 'reactions',
-  initialState,
-  reducers: {},
+  initialState: REACTIONS_INITIAL_STATE,
+  reducers: {
+    resetReactionsData: resetReactionsDataReducer,
+  },
   extraReducers: builder => {
     getReactionsReducer(builder);
   },
 });
 
+export const { resetReactionsData } = reactionsSlice.actions;
+
 export default reactionsSlice.reducer;
diff --git a/src/types/models.ts b/src/types/models.ts
index 2033c775a05a4431881a77f1f7c450d299ca244a..27b6246e82c88f5b95e699fb154a5d3292bf3633 100644
--- a/src/types/models.ts
+++ b/src/types/models.ts
@@ -13,6 +13,7 @@ import { organism } from '@/models/organism';
 import { overviewImageView } from '@/models/overviewImageView';
 import { projectSchema } from '@/models/project';
 import { reactionSchema } from '@/models/reaction';
+import { reactionLineSchema } from '@/models/reactionLineSchema';
 import { targetSchema } from '@/models/targetSchema';
 import { z } from 'zod';
 
@@ -31,5 +32,6 @@ export type BioEntityContent = z.infer<typeof bioEntityContentSchema>;
 export type BioEntityResponse = z.infer<typeof bioEntityResponseSchema>;
 export type Chemical = z.infer<typeof chemicalSchema>;
 export type Reaction = z.infer<typeof reactionSchema>;
+export type ReactionLine = z.infer<typeof reactionLineSchema>;
 export type ElementSearchResult = z.infer<typeof elementSearchResult>;
 export type ElementSearchResultType = z.infer<typeof elementSearchResultType>;
diff --git a/src/types/reactions.ts b/src/types/reactions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..44c8237a4d76618c7df9fdd5a868aaf2d23560fb
--- /dev/null
+++ b/src/types/reactions.ts
@@ -0,0 +1,3 @@
+import { Point } from './map';
+
+export type LinePoint = [Point, Point];
diff --git a/src/utils/testing/getReduxWrapperWithStore.tsx b/src/utils/testing/getReduxWrapperWithStore.tsx
index 5c799a25d2413cc0d6fffdd57fc40537bd5c29bd..d1f0c3dfe1529bbe9cb64a9d09ec1f16ac219951 100644
--- a/src/utils/testing/getReduxWrapperWithStore.tsx
+++ b/src/utils/testing/getReduxWrapperWithStore.tsx
@@ -8,7 +8,7 @@ interface WrapperProps {
 
 export type InitialStoreState = Partial<RootState>;
 
-type GetReduxWrapperUsingSliceReducer = (initialState?: InitialStoreState) => {
+export type GetReduxWrapperUsingSliceReducer = (initialState?: InitialStoreState) => {
   Wrapper: ({ children }: WrapperProps) => JSX.Element;
   store: StoreType;
 };