diff --git a/src/components/FunctionalArea/MapNavigation/MapNavigation.component.test.tsx b/src/components/FunctionalArea/MapNavigation/MapNavigation.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..051bc4d73ffb780eceff010f71b235f579a9060c
--- /dev/null
+++ b/src/components/FunctionalArea/MapNavigation/MapNavigation.component.test.tsx
@@ -0,0 +1,135 @@
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { StoreType } from '@/redux/store';
+import { initialMapDataFixture, openedMapsThreeSubmapsFixture } from '@/redux/map/map.fixtures';
+import { act, render, screen, within } from '@testing-library/react';
+import { MapNavigation } from './MapNavigation.component';
+
+const MAIN_MAP_ID = 5053;
+const HISTAMINE_MAP_ID = 5052;
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <MapNavigation />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('MapNavigation - component', () => {
+  it('should render list of currently opened maps, main map should not have close button', async () => {
+    renderComponent({
+      map: {
+        data: { ...initialMapDataFixture },
+        loading: 'succeeded',
+        error: { message: '', name: '' },
+        openedMaps: openedMapsThreeSubmapsFixture,
+      },
+    });
+
+    const mainMapButton = screen.getByRole('button', { name: 'Main map' });
+    expect(mainMapButton).toBeInTheDocument();
+
+    const histamineMapButton = screen.getByRole('button', { name: 'Histamine signaling' });
+    expect(histamineMapButton).toBeInTheDocument();
+
+    const prknMapButton = screen.getByRole('button', { name: 'PRKN substrates' });
+    expect(prknMapButton).toBeInTheDocument();
+  });
+
+  it('all maps should have close button expect main map', async () => {
+    renderComponent({
+      map: {
+        data: { ...initialMapDataFixture },
+        loading: 'succeeded',
+        error: { message: '', name: '' },
+        openedMaps: openedMapsThreeSubmapsFixture,
+      },
+    });
+
+    const mainMapButton = screen.getByRole('button', { name: 'Main map' });
+    const mainMapCloseButton = await within(mainMapButton).queryByTestId('close-icon');
+    expect(mainMapCloseButton).not.toBeInTheDocument();
+
+    const histamineMapButton = screen.getByRole('button', { name: 'Histamine signaling' });
+    const histamineMapCloseButton = await within(histamineMapButton).getByTestId('close-icon');
+    expect(histamineMapCloseButton).toBeInTheDocument();
+
+    const prknMapButton = screen.getByRole('button', { name: 'PRKN substrates' });
+    const prknMapCloseButton = await within(prknMapButton).getByTestId('close-icon');
+    expect(prknMapCloseButton).toBeInTheDocument();
+  });
+
+  it('should close map tab when clicking on close button while', async () => {
+    const { store } = renderComponent({
+      map: {
+        data: {
+          ...initialMapDataFixture,
+          modelId: MAIN_MAP_ID,
+        },
+        loading: 'succeeded',
+        error: { message: '', name: '' },
+        openedMaps: openedMapsThreeSubmapsFixture,
+      },
+    });
+
+    const histamineMapButton = screen.getByRole('button', { name: 'Histamine signaling' });
+    const histamineMapCloseButton = await within(histamineMapButton).getByTestId('close-icon');
+    await act(() => {
+      histamineMapCloseButton.click();
+    });
+
+    const {
+      map: {
+        data: { modelId },
+        openedMaps,
+      },
+    } = store.getState();
+
+    const isHistamineMapOpened = openedMaps.some(map => map.modelName === 'Histamine signaling');
+
+    expect(isHistamineMapOpened).toBe(false);
+    expect(modelId).toBe(MAIN_MAP_ID);
+  });
+
+  it('should close map and open main map if closed currently selected map', async () => {
+    const { store } = renderComponent({
+      map: {
+        data: {
+          ...initialMapDataFixture,
+          modelId: HISTAMINE_MAP_ID,
+        },
+        openedMaps: openedMapsThreeSubmapsFixture,
+        loading: 'succeeded',
+        error: { message: '', name: '' },
+      },
+    });
+
+    const histamineMapButton = screen.getByRole('button', { name: 'Histamine signaling' });
+    const histamineMapCloseButton = await within(histamineMapButton).getByTestId('close-icon');
+    await act(() => {
+      histamineMapCloseButton.click();
+    });
+
+    const {
+      map: {
+        data: { modelId },
+        openedMaps,
+      },
+    } = store.getState();
+
+    const isHistamineMapOpened = openedMaps.some(map => map.modelName === 'Histamine signaling');
+
+    expect(isHistamineMapOpened).toBe(false);
+    expect(modelId).toBe(MAIN_MAP_ID);
+  });
+});
diff --git a/src/components/FunctionalArea/MapNavigation/MapNavigation.component.tsx b/src/components/FunctionalArea/MapNavigation/MapNavigation.component.tsx
index 9a2e9c9b58ba1d0ee3fba92c5dae6cf880027025..0bc4e1d80759f06d92e40b57f2cd8bded63ac632 100644
--- a/src/components/FunctionalArea/MapNavigation/MapNavigation.component.tsx
+++ b/src/components/FunctionalArea/MapNavigation/MapNavigation.component.tsx
@@ -1,10 +1,56 @@
+import { MouseEvent } from 'react';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { mapModelIdSelector, mapOpenedMapsSelector } from '@/redux/map/map.selectors';
+import { closeMap, closeMapAndSetMainMapActive, setActiveMap } from '@/redux/map/map.slice';
+import { OppenedMap } from '@/redux/map/map.types';
 import { Button } from '@/shared/Button';
+import { Icon } from '@/shared/Icon';
+import { MAIN_MAP } from '@/redux/map/map.constants';
+import { twMerge } from 'tailwind-merge';
 
-export const MapNavigation = (): JSX.Element => (
-  <div className="h-10 w-full bg-white-pearl shadow-map-navigation-bar">
-    {/* TODO: Button is temporary until we add tabs */}
-    <Button className="h-10 bg-[#EBF4FF]" variantStyles="secondary">
-      Main map
-    </Button>
-  </div>
-);
+export const MapNavigation = (): JSX.Element => {
+  const dispatch = useAppDispatch();
+  const openedMaps = useAppSelector(mapOpenedMapsSelector);
+  const currentModelId = useAppSelector(mapModelIdSelector);
+
+  const isActive = (modelId: number): boolean => currentModelId === modelId;
+  const isNotMainMap = (modelName: string): boolean => modelName !== MAIN_MAP;
+
+  const onCloseSubmap = (event: MouseEvent<HTMLDivElement>, map: OppenedMap): void => {
+    event.stopPropagation();
+    if (isActive(map.modelId)) {
+      dispatch(closeMapAndSetMainMapActive({ modelId: map.modelId }));
+    } else {
+      dispatch(closeMap({ modelId: map.modelId }));
+    }
+  };
+
+  const onSubmapTabClick = (map: OppenedMap): void => {
+    dispatch(setActiveMap(map));
+  };
+
+  return (
+    <div className="flex h-10 w-full flex-row flex-nowrap justify-start overflow-y-auto bg-white-pearl shadow-map-navigation-bar">
+      {openedMaps.map(map => (
+        <Button
+          key={map.modelId}
+          className={twMerge(
+            'h-10 whitespace-nowrap	',
+            isActive(map.modelId) ? 'bg-[#EBF4FF]' : 'font-normal',
+          )}
+          variantStyles={isActive(map.modelId) ? 'secondary' : 'ghost'}
+          onClick={(): void => onSubmapTabClick(map)}
+        >
+          {map.modelName}
+          {isNotMainMap(map.modelName) && (
+            // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
+            <div onClick={(event): void => onCloseSubmap(event, map)} data-testid="close-icon">
+              <Icon name="close" className="ml-3 h-5 w-5 fill-font-400" />
+            </div>
+          )}
+        </Button>
+      ))}
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/DrugsAccordion/DrugsAccordion.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/DrugsAccordion/DrugsAccordion.component.test.tsx
index ff2cc2dbf7fc8816c358cf5845a45fc269fb0840..ddba126b8e91e1790232b8a8d88619d5b5ca817d 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/DrugsAccordion/DrugsAccordion.component.test.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/DrugsAccordion/DrugsAccordion.component.test.tsx
@@ -33,7 +33,7 @@ describe('DrugsAccordion - component', () => {
     renderComponent({
       drugs: { data: drugsFixture, loading: 'succeeded', error: { name: '', message: '' } },
     });
-    expect(screen.getByText('Drugs (2)')).toBeInTheDocument();
+    expect(screen.getByText('Drugs (4)')).toBeInTheDocument();
   });
   it('should display loading indicator while waiting for drug search response', () => {
     renderComponent({
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..2f3c00b7a7e10e59098b8c5ea0d950de93fca5d2
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.test.tsx
@@ -0,0 +1,63 @@
+/* eslint-disable no-magic-numbers */
+import { drugsFixture } from '@/models/fixtures/drugFixtures';
+import { StoreType } from '@/redux/store';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { render, screen } from '@testing-library/react';
+import { AccordionsDetails } from './AccordionsDetails.component';
+
+const PINS_LIST = drugsFixture.map(drug => ({
+  id: drug.id,
+  name: drug.name,
+  data: drug,
+}));
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <AccordionsDetails pinsList={PINS_LIST} />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('AccordionsDetails - component', () => {
+  it('should display name of drug', () => {
+    renderComponent();
+
+    const drugName = drugsFixture[0].name;
+
+    expect(screen.getByText(drugName, { exact: false })).toBeInTheDocument();
+  });
+  it('should display description of drug', () => {
+    renderComponent();
+
+    const drugDescription = drugsFixture[0].description;
+
+    expect(screen.getByText(drugDescription, { exact: false })).toBeInTheDocument();
+  });
+  it('should display synonyms of drug', () => {
+    renderComponent();
+
+    const firstDrugSynonym = drugsFixture[0].synonyms[0];
+    const secondDrugSynonym = drugsFixture[0].synonyms[1];
+
+    expect(screen.getByText(firstDrugSynonym, { exact: false })).toBeInTheDocument();
+    expect(screen.getByText(secondDrugSynonym, { exact: false })).toBeInTheDocument();
+  });
+  it('should display additional info about drug', () => {
+    renderComponent();
+
+    const drugAdditionalInfo = drugsFixture[0].bloodBrainBarrier;
+
+    expect(screen.getByText(drugAdditionalInfo, { exact: false })).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..9b4bad368a4a0efe4601c55db57a717a1b2490c9
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.tsx
@@ -0,0 +1,49 @@
+import {
+  Accordion,
+  AccordionItem,
+  AccordionItemButton,
+  AccordionItemHeading,
+  AccordionItemPanel,
+} from '@/shared/Accordion';
+import { PinItem } from '../PinsList/PinsList.types';
+import {
+  getAdditionalInfo,
+  getEntityDescriptions,
+  getEntityNames,
+  getEntitySynonyms,
+} from './AccordionsDetails.utils';
+
+interface AccordionsDetailsProps {
+  pinsList: PinItem[];
+}
+
+export const AccordionsDetails = ({ pinsList }: AccordionsDetailsProps): JSX.Element => {
+  return (
+    <>
+      <Accordion allowZeroExpanded className="px-6">
+        <AccordionItem>
+          <AccordionItemHeading>
+            <AccordionItemButton>Drug</AccordionItemButton>
+          </AccordionItemHeading>
+          <AccordionItemPanel>{getEntityNames(pinsList)}</AccordionItemPanel>
+        </AccordionItem>
+        <AccordionItem>
+          <AccordionItemHeading>
+            <AccordionItemButton>Description</AccordionItemButton>
+          </AccordionItemHeading>
+          <AccordionItemPanel>{getEntityDescriptions(pinsList)}</AccordionItemPanel>
+        </AccordionItem>
+        <AccordionItem>
+          <AccordionItemHeading>
+            <AccordionItemButton>Synonyms</AccordionItemButton>
+          </AccordionItemHeading>
+          <AccordionItemPanel>{getEntitySynonyms(pinsList)}</AccordionItemPanel>
+        </AccordionItem>
+      </Accordion>
+      <div className="flex justify-between px-6 py-4 text-sm font-bold">
+        <div>Blood brain barrier</div>
+        <div>{getAdditionalInfo(pinsList)}</div>
+      </div>
+    </>
+  );
+};
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.utils.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.utils.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..c59527084224d4b941aeb94a094b0739179be32d
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.utils.tsx
@@ -0,0 +1,47 @@
+import { PinItem } from '../PinsList/PinsList.types';
+
+export const getEntityNames = (pinsList: PinItem[]): string => {
+  let name = '';
+
+  pinsList.forEach(element => {
+    name += element.data.name;
+  });
+
+  return name;
+};
+
+export const getEntityDescriptions = (pinsList: PinItem[]): string => {
+  let description = '';
+
+  pinsList.forEach(element => {
+    if ('description' in element.data) {
+      description += element.data.description;
+    }
+  });
+
+  return description;
+};
+
+export const getEntitySynonyms = (pinsList: PinItem[]): string => {
+  let synonyms = '';
+
+  pinsList.forEach(element => {
+    if ('synonyms' in element.data) {
+      synonyms += element.data.synonyms.join(', ');
+    }
+  });
+
+  return synonyms;
+};
+
+export const getAdditionalInfo = (pinsList: PinItem[]): string => {
+  let additionalDetails = '';
+
+  pinsList.forEach(element => {
+    if ('bloodBrainBarrier' in element.data) {
+      additionalDetails += element.data.bloodBrainBarrier;
+    }
+  });
+
+  return additionalDetails;
+};
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx
index 44bb49c85cfbf0e96d4099d9644986d6fb316943..6aeb854e74c1c8af9a129066d698ddc68e669a04 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx
@@ -1,4 +1,5 @@
 import { assertNever } from '@/utils/assertNever';
+import { AccordionsDetails } from '../AccordionsDetails/AccordionsDetails.component';
 import { PinItem, PinType } from './PinsList.types';
 import { MirnaPinsListItem } from './PinsListItem';
 
@@ -9,18 +10,29 @@ interface PinsListProps {
 
 export const PinsList = ({ pinsList, type }: PinsListProps): JSX.Element => {
   switch (type) {
+    case 'drugs':
+      return (
+        <div className="h-[calc(100vh-198px)] overflow-auto">
+          <AccordionsDetails pinsList={pinsList} />
+          <ul className="px-6 py-2">
+            {pinsList.map(result => {
+              return result.data.targets.map(pin => (
+                <MirnaPinsListItem key={pin.name} name={pin.name} type={type} pin={pin} />
+              ));
+            })}
+          </ul>
+        </div>
+      );
     case 'bioEntity':
       return <div />;
     case 'chemicals':
       return <div />;
-    case 'drugs':
-      return <div />;
     case 'mirna':
       return (
         <ul className="h-[calc(100vh-198px)] overflow-auto px-6 py-2">
           {pinsList.map(result => {
             return result.data.targets.map(pin => (
-              <MirnaPinsListItem key={pin.name} name={pin.name} pin={pin} />
+              <MirnaPinsListItem key={pin.name} name={pin.name} type={type} pin={pin} />
             ));
           })}
         </ul>
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/MirnaPinsListItem.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/MirnaPinsListItem.component.tsx
index 2bb701d9a8b02ee9c365b18c69df00e6706afbc3..ebd97b20c8f00a7d3b7f28de1cff7af0c6cf53c6 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/MirnaPinsListItem.component.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/MirnaPinsListItem.component.tsx
@@ -2,19 +2,22 @@ import { twMerge } from 'tailwind-merge';
 import { Icon } from '@/shared/Icon';
 import { MirnaItems } from '@/types/models';
 import { getPinColor } from './PinsListItem.component.utils';
+import { PinType } from '../PinsList.types';
 
 interface MirnaPinsListItemProps {
   name: string;
+  type: PinType;
   pin: MirnaItems;
 }
 
-export const MirnaPinsListItem = ({ name, pin }: MirnaPinsListItemProps): JSX.Element => {
+export const MirnaPinsListItem = ({ name, type, pin }: MirnaPinsListItemProps): JSX.Element => {
   return (
-    <div className="mb-4 flex w-full flex-col gap-2 rounded-lg border-[1px] border-solid border-greyscale-500 p-4">
-      <div className="flex w-full flex-row gap-2">
-        <Icon name="pin" className={twMerge('mr-2 shrink-0', getPinColor('mirna'))} />
-        <p className="min-w-fit">Full name: </p>
-        <p className="w-full font-bold">{name}</p>
+    <div className="mb-4 flex w-full flex-col gap-3 rounded-lg border-[1px] border-solid border-greyscale-500 p-4">
+      <div className="flex w-full flex-row items-center gap-2">
+        <Icon name="pin" className={twMerge('mr-2 shrink-0', getPinColor(type))} />
+        <p>
+          Full name: <span className="w-full font-bold">{name}</span>
+        </p>
       </div>
       <ul className="leading-6">
         <div className="font-bold">Elements:</div>
diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx
index a143386895dc17b677d768ac5ee16ef8ac51e6f7..e056671a444f93c2d528489ab00c9b5074e8a214 100644
--- a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx
+++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx
@@ -3,9 +3,10 @@ import { IconButton } from '@/shared/IconButton';
 
 interface SubmapItemProps {
   modelName: string;
+  onOpenClick: () => void;
 }
 
-export const SubmpamItem = ({ modelName }: SubmapItemProps): JSX.Element => (
+export const SubmpamItem = ({ modelName, onOpenClick }: SubmapItemProps): JSX.Element => (
   <div className="flex flex-row flex-nowrap items-center justify-between border-b py-6">
     {modelName}
     <div className="flex flex-row flex-nowrap items-center">
@@ -16,6 +17,8 @@ export const SubmpamItem = ({ modelName }: SubmapItemProps): JSX.Element => (
         icon="chevron-right"
         className="h-6 w-6 bg-white-pearl"
         classNameIcon="fill-font-500 h-6 w-6"
+        data-testid={`${modelName}-open`}
+        onClick={onOpenClick}
       />
     </div>
   </div>
diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.test.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.test.tsx
index f37efc2cedc5f130a0c3647433411cb167dcc778..42754f4eb9456f4a661c9879116dacbe75b1e705 100644
--- a/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.test.tsx
+++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.test.tsx
@@ -2,12 +2,20 @@ import {
   InitialStoreState,
   getReduxWrapperWithStore,
 } from '@/utils/testing/getReduxWrapperWithStore';
-import { render, screen } from '@testing-library/react';
+import { act, render, screen } from '@testing-library/react';
 import { StoreType } from '@/redux/store';
 import { MODELS_MOCK_SHORT } from '@/models/mocks/modelsMock';
 import { openedDrawerSubmapsFixture } from '@/redux/drawer/drawerFixture';
+import {
+  initialMapDataFixture,
+  openedMapsInitialValueFixture,
+  openedMapsThreeSubmapsFixture,
+} from '@/redux/map/map.fixtures';
 import { SubmapsDrawer } from './SubmapsDrawer';
 
+const MAIN_MAP_ID = 5053;
+const HISTAMINE_MAP_ID = 5052;
+
 const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
   const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
 
@@ -48,4 +56,78 @@ describe('SubmapsDrawer - component', () => {
 
     expect(isOpen).toBe(false);
   });
+  it("should open submap and set it to active if it's not already opened", async () => {
+    const { store } = renderComponent({
+      models: { data: MODELS_MOCK_SHORT, loading: 'succeeded', error: { name: '', message: '' } },
+      map: {
+        data: initialMapDataFixture,
+        loading: 'succeeded',
+        error: { name: '', message: '' },
+        openedMaps: openedMapsInitialValueFixture,
+      },
+    });
+
+    const {
+      data: { modelId },
+      openedMaps,
+    } = store.getState().map;
+
+    // eslint-disable-next-line no-magic-numbers
+    expect(modelId).toBe(0);
+    expect(openedMaps).not.toContainEqual({
+      modelId: HISTAMINE_MAP_ID,
+      modelName: 'Histamine signaling',
+      lastPosition: { x: 0, y: 0, z: 0 },
+    });
+
+    const openHistamineMapButton = screen.getByTestId('Histamine signaling-open');
+    await act(() => {
+      openHistamineMapButton.click();
+    });
+
+    const {
+      data: { modelId: newModelId },
+      openedMaps: newOpenedMaps,
+    } = store.getState().map;
+
+    expect(newOpenedMaps).toContainEqual({
+      modelId: HISTAMINE_MAP_ID,
+      modelName: 'Histamine signaling',
+      lastPosition: { x: 0, y: 0, z: 0 },
+    });
+
+    expect(newModelId).toBe(HISTAMINE_MAP_ID);
+  });
+  it("should set map active if it's already opened", async () => {
+    const { store } = renderComponent({
+      models: { data: MODELS_MOCK_SHORT, loading: 'succeeded', error: { name: '', message: '' } },
+      map: {
+        data: {
+          ...initialMapDataFixture,
+          modelId: MAIN_MAP_ID,
+        },
+        openedMaps: openedMapsThreeSubmapsFixture,
+        loading: 'succeeded',
+        error: { name: '', message: '' },
+      },
+    });
+
+    const openHistamineMapButton = screen.getByTestId('Histamine signaling-open');
+    await act(() => {
+      openHistamineMapButton.click();
+    });
+
+    const {
+      map: {
+        data: { modelId },
+        openedMaps,
+      },
+    } = store.getState();
+
+    const histamineMap = openedMaps.filter(map => map.modelName === 'Histamine signaling');
+
+    // eslint-disable-next-line no-magic-numbers
+    expect(histamineMap.length).toBe(1);
+    expect(modelId).toBe(HISTAMINE_MAP_ID);
+  });
 });
diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.tsx
index 35af92d1994ef36b6de85fe734667d7344f88b75..a3b4bc1bc9e63c724abbe954915846275793bbc0 100644
--- a/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.tsx
+++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.tsx
@@ -1,17 +1,38 @@
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { modelsDataSelector } from '@/redux/models/models.selectors';
 import { DrawerHeading } from '@/shared/DrawerHeading';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { openMapAndSetActive, setActiveMap } from '@/redux/map/map.slice';
+import { MapModel } from '@/types/models';
+import { mapOpenedMapsSelector } from '@/redux/map/map.selectors';
 import { SubmpamItem } from './SubmapItem/SubmapItem.component';
 
 export const SubmapsDrawer = (): JSX.Element => {
   const models = useAppSelector(modelsDataSelector);
+  const openedMaps = useAppSelector(mapOpenedMapsSelector);
+  const dispatch = useAppDispatch();
+
+  const isMapAlreadyOpened = (modelId: number): boolean =>
+    openedMaps.some(map => map.modelId === modelId);
+
+  const onSubmapOpenClick = (model: MapModel): void => {
+    if (isMapAlreadyOpened(model.idObject)) {
+      dispatch(setActiveMap({ modelId: model.idObject }));
+    } else {
+      dispatch(openMapAndSetActive({ modelId: model.idObject, modelName: model.name }));
+    }
+  };
 
   return (
     <div data-testid="submap-drawer" className="h-full max-h-full">
       <DrawerHeading title="Submaps" />
       <ul className="h-[calc(100%-93px)] max-h-[calc(100%-93px)] overflow-y-auto px-6">
         {models.map(model => (
-          <SubmpamItem key={model.idObject} modelName={model.name} />
+          <SubmpamItem
+            key={model.idObject}
+            modelName={model.name}
+            onOpenClick={(): void => onSubmapOpenClick(model)}
+          />
         ))}
       </ul>
     </div>
diff --git a/src/components/Map/MapViewer/utils/config/getCanvasIcon.ts b/src/components/Map/MapViewer/utils/config/getCanvasIcon.ts
new file mode 100644
index 0000000000000000000000000000000000000000..163511b5a1343a680bf85dd7824d0a5cfe415a83
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/getCanvasIcon.ts
@@ -0,0 +1,64 @@
+import { PIN_PATH2D, PIN_SIZE } from '@/constants/canvas';
+import { HALF, QUARTER, THIRD } from '@/constants/dividers';
+import { DEFAULT_FONT_FAMILY } from '@/constants/font';
+import { Point } from '@/types/map';
+import { getCanvas } from '@/utils/canvas/getCanvas';
+import { getFontSizeToFit } from '@/utils/canvas/getFontSizeToFit';
+
+const SMALL_TEXT_VALUE = 1;
+const MEDIUM_TEXT_VALUE = 10;
+
+interface Args {
+  color: string;
+  value: number;
+}
+
+const drawPinOnCanvas = ({ color }: Args, ctx: CanvasRenderingContext2D): void => {
+  const path = new Path2D(PIN_PATH2D);
+  ctx.fillStyle = color;
+  ctx.fill(path);
+};
+
+const getTextWidth = (value: number): number => {
+  switch (true) {
+    case value === SMALL_TEXT_VALUE:
+      return PIN_SIZE.width / QUARTER;
+    case value < MEDIUM_TEXT_VALUE:
+      return PIN_SIZE.width / THIRD;
+    default:
+      return PIN_SIZE.width / HALF;
+  }
+};
+
+const getTextPosition = (textWidth: number, textHeight: number): Point => ({
+  x: (PIN_SIZE.width - textWidth) / HALF,
+  y: (PIN_SIZE.height - textHeight) / QUARTER,
+});
+
+const drawNumberOnCanvas = ({ value }: Args, ctx: CanvasRenderingContext2D): void => {
+  const text = `${value}`;
+  const textMetrics = ctx.measureText(text);
+
+  const textWidth = getTextWidth(value);
+  const fontSize = getFontSizeToFit(ctx, text, DEFAULT_FONT_FAMILY, textWidth);
+  const textHeight = textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent;
+  const { x, y } = getTextPosition(textWidth, textHeight);
+
+  ctx.fillStyle = 'white';
+  ctx.textBaseline = 'top';
+  ctx.font = `${fontSize}px ${DEFAULT_FONT_FAMILY}`;
+  ctx.fillText(text, x, y);
+};
+
+export const getCanvasIcon = (args: Args): HTMLCanvasElement => {
+  const canvas = getCanvas(PIN_SIZE);
+  const ctx = canvas.getContext('2d');
+  if (!ctx) {
+    return canvas;
+  }
+
+  drawPinOnCanvas(args, ctx);
+  drawNumberOnCanvas(args, ctx);
+
+  return canvas;
+};
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts b/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts
index f2c512a5cd10a2b0bf78f73bd6b9e62c44906f6b..1ed0fcc6485371ebd962bc179af3a3b8e80e90a2 100644
--- a/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts
+++ b/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts
@@ -1,5 +1,5 @@
 /* eslint-disable no-magic-numbers */
-import { MAP_DATA_INITIAL_STATE } from '@/redux/map/map.constants';
+import { MAP_DATA_INITIAL_STATE, OPENED_MAPS_INITIAL_STATE } from '@/redux/map/map.constants';
 import mapSlice from '@/redux/map/map.slice';
 import { getReduxWrapperUsingSliceReducer } from '@/utils/testing/getReduxWrapperUsingSliceReducer';
 import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
@@ -74,6 +74,7 @@ describe('useOlMapLayers - util', () => {
           name: '',
           message: '',
         },
+        openedMaps: OPENED_MAPS_INITIAL_STATE,
       },
     });
     const dummyElement = document.createElement('div');
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts b/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts
index 67d71d50060f40018ec5d515b0608a8b98bb4f92..350a1aec442b4dae172af9e58c930325d4e5b207 100644
--- a/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts
+++ b/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts
@@ -1,57 +1,24 @@
 /* eslint-disable no-magic-numbers */
-import { OPTIONS } from '@/constants/map';
-import { currentBackgroundImagePathSelector } from '@/redux/backgrounds/background.selectors';
-import { mapDataSizeSelector } from '@/redux/map/map.selectors';
-import { projectDataSelector } from '@/redux/project/project.selectors';
-import TileLayer from 'ol/layer/Tile';
-import { XYZ } from 'ol/source';
-import { useEffect, useMemo } from 'react';
-import { useSelector } from 'react-redux';
+import { useEffect } from 'react';
 import { MapConfig, MapInstance } from '../../MapViewer.types';
-import { getMapTileUrl } from './getMapTileUrl';
+import { useOlMapPinsLayer } from './useOlMapPinsLayer';
+import { useOlMapTileLayer } from './useOlMapTileLayer';
 
 interface UseOlMapLayersInput {
   mapInstance: MapInstance;
 }
 
 export const useOlMapLayers = ({ mapInstance }: UseOlMapLayersInput): MapConfig['layers'] => {
-  const mapSize = useSelector(mapDataSizeSelector);
-  const currentBackgroundImagePath = useSelector(currentBackgroundImagePathSelector);
-  const project = useSelector(projectDataSelector);
-
-  const sourceUrl = useMemo(
-    () => getMapTileUrl({ projectDirectory: project?.directory, currentBackgroundImagePath }),
-    [project?.directory, currentBackgroundImagePath],
-  );
-
-  const source = useMemo(
-    () =>
-      new XYZ({
-        url: sourceUrl,
-        maxZoom: mapSize.maxZoom,
-        minZoom: mapSize.minZoom,
-        tileSize: mapSize.tileSize,
-        wrapX: OPTIONS.wrapXInTileLayer,
-      }),
-    [sourceUrl, mapSize.maxZoom, mapSize.minZoom, mapSize.tileSize],
-  );
-
-  const tileLayer = useMemo(
-    (): TileLayer<XYZ> =>
-      new TileLayer({
-        visible: true,
-        source,
-      }),
-    [source],
-  );
+  const tileLayer = useOlMapTileLayer();
+  const pinsLayer = useOlMapPinsLayer();
 
   useEffect(() => {
     if (!mapInstance) {
       return;
     }
 
-    mapInstance.setLayers([tileLayer]);
-  }, [tileLayer, mapInstance]);
+    mapInstance.setLayers([tileLayer, pinsLayer]);
+  }, [tileLayer, pinsLayer, mapInstance]);
 
   return [tileLayer];
 };
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapPinsLayer.ts b/src/components/Map/MapViewer/utils/config/useOlMapPinsLayer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..701a25c1d4db78655b67ee74a7ec08bd45b1bbda
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/useOlMapPinsLayer.ts
@@ -0,0 +1,66 @@
+/* eslint-disable no-magic-numbers */
+import { allBioEntitesSelectorOfCurrentMap } from '@/redux/bioEntity/bioEntity.selectors';
+import { usePointToProjection } from '@/utils/map/usePointToProjection';
+import { Feature } from 'ol';
+import { Point } 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';
+
+export const useOlMapPinsLayer = (): BaseLayer => {
+  const pointToProjection = usePointToProjection();
+  const bioEntites = useSelector(allBioEntitesSelectorOfCurrentMap);
+
+  const bioEntityFeatures = useMemo(
+    () =>
+      bioEntites.map(({ bioEntity: { x, y, name, width, height } }, index) => {
+        const point = {
+          x: x + width / 2,
+          y: y + height / 2,
+        };
+
+        const feature = new Feature({
+          geometry: new Point(pointToProjection(point)),
+          name,
+        });
+
+        const style = new Style({
+          image: new Icon({
+            displacement: [0, 32],
+            anchorXUnits: 'fraction',
+            anchorYUnits: 'pixels',
+            img: getCanvasIcon({
+              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/config/useOlMapTileLayer.ts b/src/components/Map/MapViewer/utils/config/useOlMapTileLayer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..83599a293933735e1319d4692bb23b03e22d6da4
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/useOlMapTileLayer.ts
@@ -0,0 +1,45 @@
+/* eslint-disable no-magic-numbers */
+import { OPTIONS } from '@/constants/map';
+import { currentBackgroundImagePathSelector } from '@/redux/backgrounds/background.selectors';
+import { mapDataSizeSelector } from '@/redux/map/map.selectors';
+import { projectDataSelector } from '@/redux/project/project.selectors';
+import BaseLayer from 'ol/layer/Base';
+import TileLayer from 'ol/layer/Tile';
+import { XYZ } from 'ol/source';
+import { useMemo } from 'react';
+import { useSelector } from 'react-redux';
+import { getMapTileUrl } from './getMapTileUrl';
+
+export const useOlMapTileLayer = (): BaseLayer => {
+  const mapSize = useSelector(mapDataSizeSelector);
+  const currentBackgroundImagePath = useSelector(currentBackgroundImagePathSelector);
+  const project = useSelector(projectDataSelector);
+
+  const sourceUrl = useMemo(
+    () => getMapTileUrl({ projectDirectory: project?.directory, currentBackgroundImagePath }),
+    [project?.directory, currentBackgroundImagePath],
+  );
+
+  const source = useMemo(
+    () =>
+      new XYZ({
+        url: sourceUrl,
+        maxZoom: mapSize.maxZoom,
+        minZoom: mapSize.minZoom,
+        tileSize: mapSize.tileSize,
+        wrapX: OPTIONS.wrapXInTileLayer,
+      }),
+    [sourceUrl, mapSize.maxZoom, mapSize.minZoom, mapSize.tileSize],
+  );
+
+  const tileLayer = useMemo(
+    (): TileLayer<XYZ> =>
+      new TileLayer({
+        visible: true,
+        source,
+      }),
+    [source],
+  );
+
+  return tileLayer;
+};
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts b/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts
index 3f87400ff1f13608194de724b0693ed3f0d30cc3..aa6137cbcc0be43f521ac40e5f3cf16c62f1dfff 100644
--- a/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts
+++ b/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts
@@ -3,10 +3,10 @@ import mapSlice, { setMapPosition } from '@/redux/map/map.slice';
 import { getReduxWrapperUsingSliceReducer } from '@/utils/testing/getReduxWrapperUsingSliceReducer';
 import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { renderHook, waitFor } from '@testing-library/react';
+import { MAP_DATA_INITIAL_STATE, OPENED_MAPS_INITIAL_STATE } from '@/redux/map/map.constants';
 import { View } from 'ol';
 import Map from 'ol/Map';
 import React from 'react';
-import { MAP_DATA_INITIAL_STATE } from '../../../../../redux/map/map.constants';
 import { useOlMap } from '../useOlMap';
 import { useOlMapView } from './useOlMapView';
 
@@ -87,6 +87,7 @@ describe('useOlMapView - util', () => {
           name: '',
           message: '',
         },
+        openedMaps: OPENED_MAPS_INITIAL_STATE,
       },
     });
     const dummyElement = document.createElement('div');
diff --git a/src/components/Map/MapViewer/utils/listeners/onMapSingleClick.ts b/src/components/Map/MapViewer/utils/listeners/onMapSingleClick.ts
index acf6e51664ffb871b4aab35e36ba3199bbfe9a29..4b39092bc28a0846ae4e4e2c7ca7eee3bc50233b 100644
--- a/src/components/Map/MapViewer/utils/listeners/onMapSingleClick.ts
+++ b/src/components/Map/MapViewer/utils/listeners/onMapSingleClick.ts
@@ -37,10 +37,11 @@ export const handleReactionResults =
         return;
       }
 
-      const { products, reactants } = payload[FIRST];
+      const { products, reactants, modifiers } = payload[FIRST];
       const productsIds = products.map(p => p.aliasId);
       const reactantsIds = reactants.map(r => r.aliasId);
-      const bioEntitiesIds = [...productsIds, ...reactantsIds].map(identifier => String(identifier));
+      const modifiersIds = modifiers.map(m => m.aliasId);
+      const bioEntitiesIds = [...productsIds, ...reactantsIds, ...modifiersIds].map(identifier => String(identifier));
 
       dispatch(setBioEntityContent([]));
       await dispatch(
diff --git a/src/components/SPA/MinervaSPA.component.tsx b/src/components/SPA/MinervaSPA.component.tsx
index 4de3ca1fb95c0e3bbf4b82dbc85e7afffb32d033..3376b1ca88b4dbbd938d828d5e69b95675af1aad 100644
--- a/src/components/SPA/MinervaSPA.component.tsx
+++ b/src/components/SPA/MinervaSPA.component.tsx
@@ -1,17 +1,10 @@
 import { FunctionalArea } from '@/components/FunctionalArea';
 import { Map } from '@/components/Map';
+import { manrope } from '@/constants/font';
 import { useReduxBusQueryManager } from '@/utils/query-manager/useReduxBusQueryManager';
-import { Manrope } from '@next/font/google';
 import { twMerge } from 'tailwind-merge';
 import { useInitializeStore } from '../../utils/initialize/useInitializeStore';
 
-const manrope = Manrope({
-  variable: '--font-manrope',
-  display: 'swap',
-  weight: ['400', '700'],
-  subsets: ['latin'],
-});
-
 export const MinervaSPA = (): JSX.Element => {
   useInitializeStore();
   useReduxBusQueryManager();
diff --git a/src/constants/canvas.ts b/src/constants/canvas.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b9741f3001cb3defe3931b799a208860b4110879
--- /dev/null
+++ b/src/constants/canvas.ts
@@ -0,0 +1,7 @@
+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';
+
+export const PIN_SIZE = {
+  width: 25,
+  height: 32,
+};
diff --git a/src/constants/common.ts b/src/constants/common.ts
index ee434dc7c1ebfa6b43b4f2b6004ef5d042a41861..2651c7063a81f9981f27c21bce15a092c7eb5fd1 100644
--- a/src/constants/common.ts
+++ b/src/constants/common.ts
@@ -1 +1,2 @@
 export const SIZE_OF_EMPTY_ARRAY = 0;
+export const ZERO = 0;
diff --git a/src/constants/dividers.ts b/src/constants/dividers.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c73dd7aa1975e776c72961afc6d4f71f8d594cb9
--- /dev/null
+++ b/src/constants/dividers.ts
@@ -0,0 +1,3 @@
+export const HALF = 2;
+export const THIRD = 3;
+export const QUARTER = 4;
diff --git a/src/constants/errors.ts b/src/constants/errors.ts
new file mode 100644
index 0000000000000000000000000000000000000000..887f64f35d00d60ce428da9f5b4239c0d8c6cbaa
--- /dev/null
+++ b/src/constants/errors.ts
@@ -0,0 +1 @@
+export const DEFAULT_ERROR: Error = { message: '', name: '' };
diff --git a/src/constants/font.ts b/src/constants/font.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a8ea3d4d6cb31c59c237ee51062294131e3ae497
--- /dev/null
+++ b/src/constants/font.ts
@@ -0,0 +1,10 @@
+import { Manrope } from '@next/font/google';
+
+export const manrope = Manrope({
+  variable: '--font-manrope',
+  display: 'swap',
+  weight: ['400', '700'],
+  subsets: ['latin'],
+});
+
+export const DEFAULT_FONT_FAMILY = manrope.style.fontFamily;
diff --git a/src/models/mapOverlay.ts b/src/models/mapOverlay.ts
index b76cd45abde2b9bf1c4c3314040ab37e4e48a610..a22b65aa5eed7751bc3033c30998972dadadd9c5 100644
--- a/src/models/mapOverlay.ts
+++ b/src/models/mapOverlay.ts
@@ -5,8 +5,8 @@ export const mapOverlay = z.object({
   googleLicenseConsent: z.boolean(),
   creator: z.string(),
   description: z.string(),
-  genomeType: z.null(),
-  genomeVersion: z.null(),
+  genomeType: z.string().nullable(),
+  genomeVersion: z.string().nullable(),
   idObject: z.number(),
   publicOverlay: z.boolean(),
   type: z.string(),
diff --git a/src/models/reaction.ts b/src/models/reaction.ts
index 7b2dd7b1454b314195af963dc315e1cf13de6ba6..b36154d9b45d07d7a25ea14b04b1b87b50cdbf9f 100644
--- a/src/models/reaction.ts
+++ b/src/models/reaction.ts
@@ -16,7 +16,7 @@ export const reactionSchema = z.object({
     }),
   ),
   modelId: z.number(),
-  modifiers: z.array(z.unknown()),
+  modifiers: z.array(productsSchema),
   name: z.string(),
   notes: z.string(),
   products: z.array(productsSchema),
diff --git a/src/redux/backgrounds/background.mock.ts b/src/redux/backgrounds/background.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..515bb7249c74207a0435d8a220ac24da9ad55b6e
--- /dev/null
+++ b/src/redux/backgrounds/background.mock.ts
@@ -0,0 +1,60 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { MapBackground } from '@/types/models';
+import { BackgroundsState } from './backgrounds.types';
+
+export const BACKGROUND_INITIAL_STATE_MOCK: BackgroundsState = {
+  data: undefined,
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
+
+export const BACKGROUNDS_MOCK: MapBackground[] = [
+  {
+    id: 13,
+    name: 'Pathways and compartments',
+    defaultOverlay: false,
+    project: {
+      projectId: 'pdmap_appu_test',
+    },
+    creator: {
+      login: 'admin',
+    },
+    status: 'NA',
+    progress: 0,
+    description: null,
+    order: 0,
+    images: [],
+  },
+  {
+    id: 14,
+    name: 'Network',
+    defaultOverlay: false,
+    project: {
+      projectId: 'pdmap_appu_test',
+    },
+    creator: {
+      login: 'admin',
+    },
+    status: 'NA',
+    progress: 0,
+    description: null,
+    order: 1,
+    images: [],
+  },
+  {
+    id: 15,
+    name: 'Empty',
+    defaultOverlay: false,
+    project: {
+      projectId: 'pdmap_appu_test',
+    },
+    creator: {
+      login: 'admin',
+    },
+    status: 'NA',
+    progress: 0,
+    description: null,
+    order: 2,
+    images: [],
+  },
+];
diff --git a/src/redux/backgrounds/background.selectors.ts b/src/redux/backgrounds/background.selectors.ts
index 16b233972a19c5eb7edc916f74c716c41550e48b..319bfc27376c4a099fe51ee0fee14b4a2e73348d 100644
--- a/src/redux/backgrounds/background.selectors.ts
+++ b/src/redux/backgrounds/background.selectors.ts
@@ -9,6 +9,12 @@ export const backgroundsDataSelector = createSelector(
   backgrounds => backgrounds?.data || [],
 );
 
+const MAIN_BACKGROUND = 0;
+export const mainBackgroundsDataSelector = createSelector(
+  backgroundsDataSelector,
+  backgrounds => backgrounds[MAIN_BACKGROUND],
+);
+
 export const currentBackgroundSelector = createSelector(
   backgroundsDataSelector,
   mapDataSelector,
diff --git a/src/redux/bioEntity/bioEntity.mock.ts b/src/redux/bioEntity/bioEntity.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3706162e8dd2ec52452f51cdbaef0c4dd50e027a
--- /dev/null
+++ b/src/redux/bioEntity/bioEntity.mock.ts
@@ -0,0 +1,8 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { BioEntityContentsState } from './bioEntity.types';
+
+export const BIOENTITY_INITIAL_STATE_MOCK: BioEntityContentsState = {
+  data: undefined,
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
diff --git a/src/redux/bioEntity/bioEntity.selectors.ts b/src/redux/bioEntity/bioEntity.selectors.ts
index 43c3002e30980c9f6c09076cb632b6d54fa74bb3..dac3b8c71cb696d8c9a2bd6289f35aa7df5dfccd 100644
--- a/src/redux/bioEntity/bioEntity.selectors.ts
+++ b/src/redux/bioEntity/bioEntity.selectors.ts
@@ -1,6 +1,8 @@
 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 { currentModelIdSelector } from '../models/models.selectors';
 
 export const bioEntitySelector = createSelector(rootSelector, state => state.bioEntity);
 
@@ -9,6 +11,13 @@ export const loadingBioEntityStatusSelector = createSelector(
   state => state.loading,
 );
 
+export const allBioEntitesSelectorOfCurrentMap = createSelector(
+  bioEntitySelector,
+  currentModelIdSelector,
+  (state, currentModelId): BioEntityContent[] =>
+    (state?.data || []).filter(({ bioEntity }) => bioEntity.model === currentModelId),
+);
+
 export const numberOfBioEntitiesSelector = createSelector(bioEntitySelector, state =>
   state.data ? state.data.length : SIZE_OF_EMPTY_ARRAY,
 );
diff --git a/src/redux/chemicals/chemicals.mock.ts b/src/redux/chemicals/chemicals.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3b492a2e4656daa87eed1047a89ceed0049500e9
--- /dev/null
+++ b/src/redux/chemicals/chemicals.mock.ts
@@ -0,0 +1,8 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { ChemicalsState } from './chemicals.types';
+
+export const CHEMICALS_INITIAL_STATE_MOCK: ChemicalsState = {
+  data: undefined,
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
diff --git a/src/redux/drugs/drugs.mock.ts b/src/redux/drugs/drugs.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..884c8de9aa8d89a6c2b830ed85427b0a77e06f37
--- /dev/null
+++ b/src/redux/drugs/drugs.mock.ts
@@ -0,0 +1,8 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { DrugsState } from './drugs.types';
+
+export const DRUGS_INITIAL_STATE_MOCK: DrugsState = {
+  data: undefined,
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
diff --git a/src/redux/drugs/drugs.selectors.ts b/src/redux/drugs/drugs.selectors.ts
index 7a1d3eacacbf0fee4cd7093f4c0255f4c910af51..af9a8d7fa58659446deb5e8685b489cc67cfdcbf 100644
--- a/src/redux/drugs/drugs.selectors.ts
+++ b/src/redux/drugs/drugs.selectors.ts
@@ -5,6 +5,16 @@ import { createSelector } from '@reduxjs/toolkit';
 export const drugsSelector = createSelector(rootSelector, state => state.drugs);
 
 export const loadingDrugsStatusSelector = createSelector(drugsSelector, state => state.loading);
-export const numberOfDrugsSelector = createSelector(drugsSelector, state =>
-  state.data ? state.data.length : SIZE_OF_EMPTY_ARRAY,
-);
+export const numberOfDrugsSelector = createSelector(drugsSelector, state => {
+  if (!state.data) {
+    return SIZE_OF_EMPTY_ARRAY;
+  }
+
+  let numberOfDrugs = 0;
+
+  state.data.forEach(element => {
+    numberOfDrugs += element.targets.length;
+  });
+
+  return numberOfDrugs;
+});
diff --git a/src/redux/map/map.constants.ts b/src/redux/map/map.constants.ts
index de82f296b19012d682782e59e10363210eeb285e..333a20627dc73fa4844b919b580d2231b1539c13 100644
--- a/src/redux/map/map.constants.ts
+++ b/src/redux/map/map.constants.ts
@@ -5,13 +5,20 @@ import {
   DEFAULT_MIN_ZOOM,
   DEFAULT_TILE_SIZE,
 } from '@/constants/map';
-import { MapData } from './map.types';
+import { Point } from '@/types/map';
+import { MapData, OppenedMap } from './map.types';
+
+export const MAIN_MAP = 'Main map';
+
+export const MODEL_ID_DEFAULT: number = 0;
+
+export const BACKGROUND_ID_DEFAULT: number = 0;
 
 export const MAP_DATA_INITIAL_STATE: MapData = {
   projectId: PROJECT_ID,
   meshId: '',
-  modelId: 0,
-  backgroundId: 0,
+  modelId: MODEL_ID_DEFAULT,
+  backgroundId: BACKGROUND_ID_DEFAULT,
   overlaysIds: [],
   position: {
     last: DEFAULT_CENTER_POINT,
@@ -29,5 +36,10 @@ export const MAP_DATA_INITIAL_STATE: MapData = {
     maxZoom: DEFAULT_MAX_ZOOM,
   },
 };
+export const DEFAULT_POSITION: Point = { x: 0, y: 0, z: 0 };
+
+export const OPENED_MAPS_INITIAL_STATE: OppenedMap[] = [
+  { modelId: MODEL_ID_DEFAULT, modelName: MAIN_MAP, lastPosition: DEFAULT_POSITION },
+];
 
 export const MIDDLEWARE_ALLOWED_ACTIONS: string[] = ['map/setMapData'];
diff --git a/src/redux/map/map.fixtures.ts b/src/redux/map/map.fixtures.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5cb2f16fe2683d2988f2a7bd16aff6e95a558eaf
--- /dev/null
+++ b/src/redux/map/map.fixtures.ts
@@ -0,0 +1,42 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { MapData, MapState, OppenedMap } from './map.types';
+
+export const openedMapsInitialValueFixture: OppenedMap[] = [
+  { modelId: 0, modelName: 'Main map', lastPosition: { x: 0, y: 0, z: 0 } },
+];
+
+export const openedMapsThreeSubmapsFixture: OppenedMap[] = [
+  { modelId: 5053, modelName: 'Main map', lastPosition: { x: 0, y: 0, z: 0 } },
+  { modelId: 5052, modelName: 'Histamine signaling', lastPosition: { x: 0, y: 0, z: 0 } },
+  { modelId: 5054, modelName: 'PRKN substrates', lastPosition: { x: 0, y: 0, z: 0 } },
+];
+
+export const initialMapDataFixture: MapData = {
+  projectId: 'pdmap',
+  meshId: '',
+  modelId: 0,
+  backgroundId: 0,
+  overlaysIds: [],
+  position: {
+    initial: { x: 0, y: 0, z: 5 },
+    last: { x: 0, y: 0, z: 5 },
+  },
+  show: {
+    legend: false,
+    comments: false,
+  },
+  size: {
+    width: 0,
+    height: 0,
+    tileSize: 256,
+    minZoom: 2,
+    maxZoom: 9,
+  },
+};
+
+export const initialMapStateFixture: MapState = {
+  data: initialMapDataFixture,
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+  openedMaps: openedMapsInitialValueFixture,
+};
diff --git a/src/redux/map/map.reducers.ts b/src/redux/map/map.reducers.ts
index 7dc80074bba59f069adb94676a3634860a7d8ee1..b0ad81bf535fa81d7f6dc1678a8b2b6d7eaeee06 100644
--- a/src/redux/map/map.reducers.ts
+++ b/src/redux/map/map.reducers.ts
@@ -1,7 +1,21 @@
 import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
+import { ZERO } from '@/constants/common';
+import {
+  CloseMapAction,
+  MapState,
+  OpenMapAndSetActiveAction,
+  SetActiveMapAction,
+  SetMapDataAction,
+  SetMapPositionDataAction,
+} from './map.types';
+import { MAIN_MAP } from './map.constants';
 import { getPointMerged } from '../../utils/object/getPointMerged';
-import { initMapData, initMapPosition } from './map.thunks';
-import { MapState, SetMapDataAction, SetMapPositionDataAction } from './map.types';
+import {
+  initMapBackground,
+  initMapPosition,
+  initMapSizeAndModelId,
+  initOpenedMaps,
+} from './map.thunks';
 
 export const setMapDataReducer = (state: MapState, action: SetMapDataAction): void => {
   const payload = action.payload || {};
@@ -26,32 +40,72 @@ export const setMapPositionReducer = (state: MapState, action: SetMapPositionDat
   };
 };
 
-export const getMapReducers = (builder: ActionReducerMapBuilder<MapState>): void => {
-  builder.addCase(initMapData.pending, state => {
-    state.loading = 'pending';
-  });
-  builder.addCase(initMapData.fulfilled, (state, action) => {
-    const payload = action.payload || {};
-    state.data = { ...state.data, ...payload };
-    state.loading = 'succeeded';
-  });
-  builder.addCase(initMapData.rejected, state => {
-    state.loading = 'failed';
-    // TODO to discuss manage state of failure
+const updateLastPositionOfCurrentlyActiveMap = (state: MapState): void => {
+  const currentMapId = state.data.modelId;
+  const currentOpenedMap = state.openedMaps.find(openedMap => openedMap.modelId === currentMapId);
+  if (currentOpenedMap) {
+    currentOpenedMap.lastPosition = state.data.position.last;
+  }
+};
+
+export const setActiveMapReducer = (state: MapState, action: SetActiveMapAction): void => {
+  updateLastPositionOfCurrentlyActiveMap(state);
+  state.data.modelId = action.payload.modelId;
+};
+
+export const openMapAndSetActiveReducer = (
+  state: MapState,
+  action: OpenMapAndSetActiveAction,
+): void => {
+  updateLastPositionOfCurrentlyActiveMap(state);
+
+  state.openedMaps.push({
+    modelId: action.payload.modelId,
+    modelName: action.payload.modelName,
+    lastPosition: { x: 0, y: 0, z: 0 },
   });
+  state.data.modelId = action.payload.modelId;
+};
+
+export const closeMapReducer = (state: MapState, action: CloseMapAction): void => {
+  state.openedMaps = state.openedMaps.filter(
+    openedMap => openedMap.modelId !== action.payload.modelId,
+  );
 };
 
-export const getMapPositionReducers = (builder: ActionReducerMapBuilder<MapState>): void => {
-  builder.addCase(initMapPosition.pending, state => {
-    state.loading = 'pending';
+export const closeMapAndSetMainMapActiveReducer = (
+  state: MapState,
+  action: CloseMapAction,
+): void => {
+  state.openedMaps = state.openedMaps.filter(
+    openedMap => openedMap.modelId !== action.payload.modelId,
+  );
+  state.data.modelId =
+    state.openedMaps.find(openedMap => openedMap.modelName === MAIN_MAP)?.modelId || ZERO;
+};
+
+export const initMapSizeAndModelIdReducer = (builder: ActionReducerMapBuilder<MapState>): void => {
+  builder.addCase(initMapSizeAndModelId.fulfilled, (state, action) => {
+    state.data.modelId = action.payload.modelId;
+    state.data.size = action.payload.size;
   });
+};
+
+export const initMapPositionReducers = (builder: ActionReducerMapBuilder<MapState>): void => {
   builder.addCase(initMapPosition.fulfilled, (state, action) => {
-    const payload = action.payload || {};
-    state.data = { ...state.data, ...payload };
+    state.data.position = action.payload;
+  });
+};
+
+export const initMapBackgroundsReducer = (builder: ActionReducerMapBuilder<MapState>): void => {
+  builder.addCase(initMapBackground.fulfilled, (state, action) => {
+    state.data.backgroundId = action.payload;
     state.loading = 'succeeded';
   });
-  builder.addCase(initMapPosition.rejected, state => {
-    state.loading = 'failed';
-    // TODO to discuss manage state of failure
+};
+
+export const initOpenedMapsReducer = (builder: ActionReducerMapBuilder<MapState>): void => {
+  builder.addCase(initOpenedMaps.fulfilled, (state, action) => {
+    state.openedMaps = action.payload;
   });
 };
diff --git a/src/redux/map/map.selectors.ts b/src/redux/map/map.selectors.ts
index bc71ec9840e6bd2c6700461b528082e707bfd217..3f9d9d869324b43b48093632cfd02a7e5e493ff0 100644
--- a/src/redux/map/map.selectors.ts
+++ b/src/redux/map/map.selectors.ts
@@ -9,11 +9,20 @@ export const mapDataSizeSelector = createSelector(mapDataSelector, map => map.si
 
 export const mapDataPositionSelector = createSelector(mapDataSelector, map => map.position);
 
+export const mapOpenedMapsSelector = createSelector(mapSelector, state => state.openedMaps);
+
+export const mapModelIdSelector = createSelector(mapDataSelector, map => map.modelId);
 export const mapDataInitialPositionSelector = createSelector(
   mapDataPositionSelector,
   position => position.initial,
 );
 
+export const mapOpenedMapPositionByIdSelector = createSelector(
+  [mapOpenedMapsSelector, (_state, modelId: number): number => modelId],
+  (openedMaps, modelId) =>
+    openedMaps.find(openedMap => openedMap.modelId === modelId)?.lastPosition,
+);
+
 export const mapDataLastPositionSelector = createSelector(
   mapDataPositionSelector,
   position => position.last,
diff --git a/src/redux/map/map.slice.ts b/src/redux/map/map.slice.ts
index 49a21589200ba0f0c3c10f2931310eac663cca8f..ca51213ca667fc5087cec6f45d988c61f508d8dc 100644
--- a/src/redux/map/map.slice.ts
+++ b/src/redux/map/map.slice.ts
@@ -1,10 +1,16 @@
 import { createSlice } from '@reduxjs/toolkit';
-import { MAP_DATA_INITIAL_STATE } from './map.constants';
+import { MAP_DATA_INITIAL_STATE, OPENED_MAPS_INITIAL_STATE } from './map.constants';
 import {
-  getMapPositionReducers,
-  getMapReducers,
+  closeMapAndSetMainMapActiveReducer,
+  closeMapReducer,
+  openMapAndSetActiveReducer,
+  setActiveMapReducer,
   setMapDataReducer,
+  initMapPositionReducers,
   setMapPositionReducer,
+  initOpenedMapsReducer,
+  initMapSizeAndModelIdReducer,
+  initMapBackgroundsReducer,
 } from './map.reducers';
 import { MapState } from './map.types';
 
@@ -12,6 +18,7 @@ const initialState: MapState = {
   data: MAP_DATA_INITIAL_STATE,
   loading: 'idle',
   error: { name: '', message: '' },
+  openedMaps: OPENED_MAPS_INITIAL_STATE,
 };
 
 const mapSlice = createSlice({
@@ -19,14 +26,27 @@ const mapSlice = createSlice({
   initialState,
   reducers: {
     setMapData: setMapDataReducer,
+    setActiveMap: setActiveMapReducer,
+    openMapAndSetActive: openMapAndSetActiveReducer,
+    closeMap: closeMapReducer,
+    closeMapAndSetMainMapActive: closeMapAndSetMainMapActiveReducer,
     setMapPosition: setMapPositionReducer,
   },
   extraReducers: builder => {
-    getMapReducers(builder);
-    getMapPositionReducers(builder);
+    initMapPositionReducers(builder);
+    initMapSizeAndModelIdReducer(builder);
+    initMapBackgroundsReducer(builder);
+    initOpenedMapsReducer(builder);
   },
 });
 
-export const { setMapData, setMapPosition } = mapSlice.actions;
+export const {
+  setMapData,
+  setActiveMap,
+  openMapAndSetActive,
+  closeMap,
+  closeMapAndSetMainMapActive,
+  setMapPosition,
+} = mapSlice.actions;
 
 export default mapSlice.reducer;
diff --git a/src/redux/map/map.thunks.test.ts b/src/redux/map/map.thunks.test.ts
index d717ad71b5c557ab908eed821bdd5f1616325c01..69a2e9e110194858eb8e5a986dc2ce0201afefdb 100644
--- a/src/redux/map/map.thunks.test.ts
+++ b/src/redux/map/map.thunks.test.ts
@@ -1,20 +1,11 @@
-import { PROJECT_ID } from '@/constants';
-import { backgroundsFixture } from '@/models/fixtures/backgroundsFixture';
-import { modelsFixture } from '@/models/fixtures/modelsFixture';
-import { overlaysFixture } from '@/models/fixtures/overlaysFixture';
+import { MODELS_MOCK } from '@/models/mocks/modelsMock';
+/* eslint-disable no-magic-numbers */
 import { QueryData } from '@/types/query';
-import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
-import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
-import { HttpStatusCode } from 'axios';
-import { apiPath } from '../apiPath';
-import { backgroundsDataSelector } from '../backgrounds/background.selectors';
-import { modelsDataSelector } from '../models/models.selectors';
-import { overlaysDataSelector } from '../overlays/overlays.selectors';
-import { AppDispatch, StoreType } from '../store';
-import { initMapData } from './map.thunks';
-import { InitMapDataActionPayload } from './map.types';
-
-const mockedAxiosClient = mockNetworkResponse();
+import { BACKGROUNDS_MOCK, BACKGROUND_INITIAL_STATE_MOCK } from '../backgrounds/background.mock';
+import { RootState } from '../store';
+import { INITIAL_STORE_STATE_MOCK } from '../root/root.fixtures';
+import { MODELS_INITIAL_STATE_MOCK } from '../models/models.mock';
+import { getBackgroundId, getInitMapPosition, getInitMapSizeAndModelId } from './map.thunks';
 
 const EMPTY_QUERY_DATA: QueryData = {
   modelId: undefined,
@@ -22,74 +13,98 @@ const EMPTY_QUERY_DATA: QueryData = {
   initialPosition: undefined,
 };
 
-describe('map thunks', () => {
-  describe('initMapData - thunk', () => {
-    describe('when API is returning valid data', () => {
-      let store = {} as StoreType;
-      let payload = {} as InitMapDataActionPayload;
+const QUERY_DATA_WITH_BG: QueryData = {
+  modelId: undefined,
+  backgroundId: 21,
+  initialPosition: undefined,
+};
 
-      beforeAll(async () => {
-        mockedAxiosClient.resetHandlers();
-        mockedAxiosClient.onGet(apiPath.getModelsString()).reply(HttpStatusCode.Ok, modelsFixture);
-        mockedAxiosClient
-          .onGet(apiPath.getAllOverlaysByProjectIdQuery(PROJECT_ID, { publicOverlay: true }))
-          .reply(HttpStatusCode.Ok, overlaysFixture);
-        mockedAxiosClient
-          .onGet(apiPath.getAllBackgroundsByProjectIdQuery(PROJECT_ID))
-          .reply(HttpStatusCode.Ok, backgroundsFixture);
+const QUERY_DATA_WITH_MODELID: QueryData = {
+  modelId: 5054,
+  backgroundId: undefined,
+  initialPosition: undefined,
+};
 
-        store = getReduxWrapperWithStore().store;
-        const dispatch = store.dispatch as AppDispatch;
-        payload = (await dispatch(initMapData({ queryData: EMPTY_QUERY_DATA })))
-          .payload as InitMapDataActionPayload;
-      });
+const QUERY_DATA_WITH_POSITION: QueryData = {
+  modelId: undefined,
+  backgroundId: undefined,
+  initialPosition: {
+    x: 21,
+    y: 3,
+    z: 7,
+  },
+};
 
-      it('should fetch backgrounds data in store', async () => {
-        const data = backgroundsDataSelector(store.getState());
-        expect(data).toEqual(backgroundsFixture);
-      });
+const STATE_WITH_MODELS: RootState = {
+  ...INITIAL_STORE_STATE_MOCK,
+  models: { ...MODELS_INITIAL_STATE_MOCK, data: MODELS_MOCK },
+};
 
-      it('should fetch overlays data in store', async () => {
-        const data = overlaysDataSelector(store.getState());
-        expect(data).toEqual(overlaysFixture);
-      });
+describe('map thunks - utils', () => {
+  describe('getBackgroundId', () => {
+    it('should return backgroundId value from queryData', () => {
+      const backgroundId = getBackgroundId(INITIAL_STORE_STATE_MOCK, QUERY_DATA_WITH_BG);
+      expect(backgroundId).toBe(21);
+    });
+    it('should return main map background id if query param does not include background id', () => {
+      const store: RootState = {
+        ...INITIAL_STORE_STATE_MOCK,
+        backgrounds: { ...BACKGROUND_INITIAL_STATE_MOCK, data: BACKGROUNDS_MOCK },
+      };
+      const backgroundId = getBackgroundId(store, EMPTY_QUERY_DATA);
 
-      it('should fetch models data in store', async () => {
-        const data = modelsDataSelector(store.getState());
-        expect(data).toEqual(modelsFixture);
-      });
+      expect(backgroundId).toBe(13);
+    });
+    it('should return default value (0) if query data does not include backgroundId and could not find main background in the store', () => {
+      const backgroundId = getBackgroundId(INITIAL_STORE_STATE_MOCK, EMPTY_QUERY_DATA);
 
-      it('should return valid payload', () => {
-        const FIRST = 0;
+      expect(backgroundId).toBe(0);
+    });
+  });
 
-        expect(payload).toMatchObject({
-          modelId: modelsFixture[FIRST].idObject,
-          backgroundId: backgroundsFixture[FIRST].id,
-        });
+  describe('getInitMapPosition', () => {
+    it('should return valid map position from query params ', () => {
+      const position = getInitMapPosition(STATE_WITH_MODELS, QUERY_DATA_WITH_POSITION);
+      expect(position).toEqual({
+        initial: { x: 21, y: 3, z: 7 },
+        last: { x: 21, y: 3, z: 7 },
       });
     });
 
-    describe('when API is returning empty array', () => {
-      let store = {} as StoreType;
-      let payload = {} as InitMapDataActionPayload;
+    it('should return valid map position if query params do not include position', () => {
+      const position = getInitMapPosition(STATE_WITH_MODELS, EMPTY_QUERY_DATA);
+      expect(position).toEqual({
+        initial: { x: 13389.625, y: 6751.5, z: 5 },
+        last: { x: 13389.625, y: 6751.5, z: 5 },
+      });
+    });
+    it('should return default map position', () => {
+      const position = getInitMapPosition(INITIAL_STORE_STATE_MOCK, EMPTY_QUERY_DATA);
+
+      expect(position).toEqual({ initial: { x: 0, y: 0, z: 0 }, last: { x: 0, y: 0, z: 0 } });
+    });
+  });
 
-      beforeEach(async () => {
-        mockedAxiosClient.onGet(apiPath.getModelsString()).reply(HttpStatusCode.Ok, []);
-        mockedAxiosClient
-          .onGet(apiPath.getAllOverlaysByProjectIdQuery(PROJECT_ID, { publicOverlay: true }))
-          .reply(HttpStatusCode.Ok, []);
-        mockedAxiosClient
-          .onGet(apiPath.getAllBackgroundsByProjectIdQuery(PROJECT_ID))
-          .reply(HttpStatusCode.Ok, []);
+  describe('getInitMapSizeAndModelId', () => {
+    it('should return correct mapsize and modelid when modelId is provided in queryData', () => {
+      const payload = getInitMapSizeAndModelId(STATE_WITH_MODELS, QUERY_DATA_WITH_MODELID);
 
-        store = getReduxWrapperWithStore().store;
-        const dispatch = store.dispatch as AppDispatch;
-        payload = (await dispatch(initMapData({ queryData: EMPTY_QUERY_DATA })))
-          .payload as InitMapDataActionPayload;
+      expect(payload).toEqual({
+        modelId: 5054,
+        size: { height: 1171.9429798877356, maxZoom: 5, minZoom: 2, tileSize: 256, width: 1652.75 },
       });
-
-      it('should return empty payload', () => {
-        expect(payload).toStrictEqual({});
+    });
+    it('should return correct mapsize and modelId if query params do not include modelId', () => {
+      const payload = getInitMapSizeAndModelId(STATE_WITH_MODELS, EMPTY_QUERY_DATA);
+      expect(payload).toEqual({
+        modelId: 5053,
+        size: {
+          height: 13503,
+          maxZoom: 9,
+          minZoom: 2,
+          tileSize: 256,
+          width: 26779.25,
+        },
       });
     });
   });
diff --git a/src/redux/map/map.thunks.ts b/src/redux/map/map.thunks.ts
index 0ebf33265655e61b9e1ad0e382a479b9c8076a31..f2ea946bf66c0f1086d3e73696fca480d42d1ede 100644
--- a/src/redux/map/map.thunks.ts
+++ b/src/redux/map/map.thunks.ts
@@ -1,72 +1,155 @@
-import { PROJECT_ID } from '@/constants';
-import { QueryData } from '@/types/query';
-import { GetUpdatedMapDataResult, getUpdatedMapData } from '@/utils/map/getUpdatedMapData';
+/* eslint-disable no-magic-numbers */
 import { createAsyncThunk } from '@reduxjs/toolkit';
-import { backgroundsDataSelector } from '../backgrounds/background.selectors';
-import { getAllBackgroundsByProjectId } from '../backgrounds/backgrounds.thunks';
-import { modelsDataSelector } from '../models/models.selectors';
-import { getModels } from '../models/models.thunks';
-import { getAllPublicOverlaysByProjectId } from '../overlays/overlays.thunks';
+import { ZERO } from '@/constants/common';
+import { QueryData } from '@/types/query';
+import { DEFAULT_ZOOM } from '@/constants/map';
+import { getPointMerged } from '@/utils/object/getPointMerged';
 import type { AppDispatch, RootState } from '../store';
 import {
-  InitMapDataActionParams,
-  InitMapDataActionPayload,
-  SetMapPositionDataActionPayload,
+  InitMapBackgroundActionPayload,
+  InitMapBackgroundParams,
+  InitMapPositionActionPayload,
+  InitMapPositionParams,
+  InitMapSizeAndModelIdActionPayload,
+  InitMapSizeAndModelIdParams,
+  InitOpenedMapsActionPayload,
+  InitOpenedMapsProps,
+  MapSizeAndModelId,
+  OppenedMap,
+  Position,
 } from './map.types';
+import { mainBackgroundsDataSelector } from '../backgrounds/background.selectors';
+import {
+  currentModelSelector,
+  mainMapModelSelector,
+  modelByIdSelector,
+  modelsDataSelector,
+} from '../models/models.selectors';
+import { DEFAULT_POSITION, MAIN_MAP } from './map.constants';
+
+/** UTILS - in the same file because of dependancy cycle */
+
+export const getBackgroundId = (state: RootState, queryData: QueryData): number => {
+  const mainMapBackground = mainBackgroundsDataSelector(state);
+  const backgroundId = queryData?.backgroundId || mainMapBackground?.id || ZERO;
+
+  return backgroundId;
+};
+
+export const getInitMapPosition = (state: RootState, queryData: QueryData): Position => {
+  const mainMapModel = mainMapModelSelector(state);
+  const modelId = queryData?.modelId || mainMapModel?.idObject || ZERO;
+  const currentModel = modelByIdSelector(state, modelId);
+  const position = queryData?.initialPosition;
+  const HALF = 2;
 
-const getInitMapDataPayload = (
+  if (!currentModel) {
+    return {
+      last: DEFAULT_POSITION,
+      initial: DEFAULT_POSITION,
+    };
+  }
+
+  const defaultPosition = {
+    x: currentModel.defaultCenterX ?? currentModel.width / HALF,
+    y: currentModel.defaultCenterY ?? currentModel.height / HALF,
+    z: currentModel.defaultZoomLevel ?? DEFAULT_ZOOM,
+  };
+
+  const mergedPosition = getPointMerged(position || {}, defaultPosition);
+
+  return {
+    last: mergedPosition,
+    initial: mergedPosition,
+  };
+};
+
+export const getInitMapSizeAndModelId = (
   state: RootState,
   queryData: QueryData,
-): GetUpdatedMapDataResult | object => {
+): MapSizeAndModelId => {
+  const mainMapModel = mainMapModelSelector(state);
+  const modelId = queryData?.modelId || mainMapModel?.idObject || ZERO;
+  const currentModel = modelByIdSelector(state, modelId);
+
+  return {
+    modelId: currentModel?.idObject || ZERO,
+    size: {
+      width: currentModel?.width || ZERO,
+      height: currentModel?.height || ZERO,
+      tileSize: currentModel?.tileSize || ZERO,
+      minZoom: currentModel?.minZoom || ZERO,
+      maxZoom: currentModel?.maxZoom || ZERO,
+    },
+  };
+};
+
+export const getOpenedMaps = (state: RootState, queryData: QueryData): OppenedMap[] => {
   const FIRST = 0;
   const models = modelsDataSelector(state);
-  const backgrounds = backgroundsDataSelector(state);
-  const modelId = queryData?.modelId || models?.[FIRST]?.idObject;
-  const backgroundId = queryData?.backgroundId || backgrounds?.[FIRST]?.id;
-  const model = models.find(({ idObject }) => idObject === modelId);
-  const background = backgrounds.find(({ id }) => id === backgroundId);
-  const position = queryData?.initialPosition;
+  const currentModel = currentModelSelector(state);
+  const mainMapId = models?.[FIRST]?.idObject || ZERO;
 
-  if (!model || !background) {
-    return {};
-  }
+  const openedMaps: OppenedMap[] = [
+    { modelId: mainMapId, modelName: MAIN_MAP, lastPosition: DEFAULT_POSITION },
+  ];
 
-  return getUpdatedMapData({
-    model,
-    background,
-    position: {
-      last: position,
-      initial: position,
-    },
-  });
+  if (queryData.modelId !== mainMapId) {
+    openedMaps.push({
+      modelId: currentModel?.idObject || ZERO,
+      modelName: currentModel?.name || '',
+      lastPosition: { ...DEFAULT_POSITION, ...queryData.initialPosition },
+    });
+  }
+  return openedMaps;
 };
 
-export const initMapData = createAsyncThunk<
-  InitMapDataActionPayload,
-  InitMapDataActionParams,
+/** THUNKS  */
+
+export const initMapSizeAndModelId = createAsyncThunk<
+  InitMapSizeAndModelIdActionPayload,
+  InitMapSizeAndModelIdParams,
   { dispatch: AppDispatch; state: RootState }
 >(
-  'map/initMapData',
-  async ({ queryData }, { dispatch, getState }): Promise<InitMapDataActionPayload> => {
-    await Promise.all([
-      dispatch(getAllBackgroundsByProjectId(PROJECT_ID)),
-      dispatch(getAllPublicOverlaysByProjectId(PROJECT_ID)),
-      dispatch(getModels()),
-    ]);
-
+  'map/initMapSizeAndModelId',
+  async ({ queryData }, { getState }): Promise<InitMapSizeAndModelIdActionPayload> => {
     const state = getState();
-    return getInitMapDataPayload(state, queryData);
+
+    return getInitMapSizeAndModelId(state, queryData);
   },
 );
 
 export const initMapPosition = createAsyncThunk<
-  InitMapDataActionPayload,
-  InitMapDataActionParams,
+  InitMapPositionActionPayload,
+  InitMapPositionParams,
   { dispatch: AppDispatch; state: RootState }
 >(
   'map/initMapPosition',
-  async ({ queryData }, { getState }): Promise<SetMapPositionDataActionPayload> => {
+  async ({ queryData }, { getState }): Promise<InitMapPositionActionPayload> => {
+    const state = getState();
+
+    return getInitMapPosition(state, queryData);
+  },
+);
+
+export const initMapBackground = createAsyncThunk<
+  InitMapBackgroundActionPayload,
+  InitMapBackgroundParams,
+  { dispatch: AppDispatch; state: RootState }
+>(
+  'map/initMapBackground',
+  async ({ queryData }, { getState }): Promise<InitMapBackgroundActionPayload> => {
     const state = getState();
-    return getInitMapDataPayload(state, queryData);
+    return getBackgroundId(state, queryData);
   },
 );
+
+export const initOpenedMaps = createAsyncThunk<
+  InitOpenedMapsActionPayload,
+  InitOpenedMapsProps,
+  { dispatch: AppDispatch; state: RootState }
+>('appInit/initOpenedMaps', async ({ queryData }, { getState }): Promise<OppenedMap[]> => {
+  const state = getState();
+
+  return getOpenedMaps(state, queryData);
+});
diff --git a/src/redux/map/map.types.ts b/src/redux/map/map.types.ts
index db099d1113ae97fda4e7186da1db597566aee802..bd641cd7708a0116fe2a8ba12741733b4a9ac1f8 100644
--- a/src/redux/map/map.types.ts
+++ b/src/redux/map/map.types.ts
@@ -11,6 +11,17 @@ export interface MapSize {
   maxZoom: number;
 }
 
+export type OppenedMap = {
+  modelId: number;
+  modelName: string;
+  lastPosition: Point;
+};
+
+export type Position = {
+  initial: Point;
+  last: Point;
+};
+
 export type MapData = {
   projectId: string;
   meshId: string;
@@ -18,17 +29,14 @@ export type MapData = {
   backgroundId: number;
   overlaysIds: number[];
   size: MapSize;
-  position: {
-    initial: Point;
-    last: Point;
-  };
+  position: Position;
   show: {
     legend: boolean;
     comments: boolean;
   };
 };
 
-export type MapState = FetchDataState<MapData, MapData>;
+export type MapState = FetchDataState<MapData, MapData> & { openedMaps: OppenedMap[] };
 
 export type SetMapDataActionPayload =
   | (Omit<Partial<MapData>, 'position' | 'projectId'> & {
@@ -36,17 +44,29 @@ export type SetMapDataActionPayload =
     })
   | undefined;
 
+export type UpdateOpenedMainMapActionPayload = Pick<OppenedMap, 'modelId' | 'lastPosition'>;
+
+export type UpdateOpenedMainMapAction = PayloadAction<UpdateOpenedMainMapActionPayload>;
+
 export type SetMapDataAction = PayloadAction<SetMapDataActionPayload>;
 
-export type InitMapDataActionParams = { queryData: QueryData };
+export type SetActiveMapActionPayload = Pick<OppenedMap, 'modelId'>;
 
-export type InitMapDataActionPayload = SetMapDataActionPayload | object;
+export type SetActiveMapAction = PayloadAction<SetActiveMapActionPayload>;
 
-export type InitMapDataAction = PayloadAction<SetMapDataAction>;
+export type SetMainMapModelIdAction = PayloadAction<SetActiveMapActionPayload>;
 
-export type MiddlewareAllowedAction = PayloadAction<
-  SetMapDataActionPayload | InitMapDataActionPayload
->;
+export type OpenMapAndSetActivePayload = Pick<OppenedMap, 'modelId' | 'modelName'>;
+
+export type OpenMapAndSetActiveAction = PayloadAction<OpenMapAndSetActivePayload>;
+
+export type CloseMapActionPayload = Pick<OppenedMap, 'modelId'>;
+
+export type CloseMapAction = PayloadAction<CloseMapActionPayload>;
+
+export type InitMapDataActionParams = { queryData: QueryData };
+
+export type InitMapDataAction = PayloadAction<SetMapDataAction>;
 
 export type SetMapDataByQueryDataActionParams = { queryData: QueryData };
 
@@ -55,6 +75,41 @@ export type SetMapDataByQueryDataActionPayload = Pick<
   'modelId' | 'backgroundId' | 'position'
 >;
 
-export type SetMapPositionDataActionPayload = Pick<MapData, 'position'> | object;
+export type GetUpdatedMapDataResult = Pick<
+  MapData,
+  'modelId' | 'backgroundId' | 'size' | 'position'
+>;
+
+export type SetMapPositionDataActionPayload = GetUpdatedMapDataResult | object;
 
 export type SetMapPositionDataAction = PayloadAction<SetMapPositionDataActionPayload>;
+
+export type InitMapDataActionPayload = {
+  data: GetUpdatedMapDataResult | object;
+  openedMaps: OppenedMap[];
+};
+export type MiddlewareAllowedAction = PayloadAction<
+  SetMapDataActionPayload | InitMapDataActionPayload
+>;
+
+export type InitOpenedMapsActionPayload = OppenedMap[];
+
+export type InitOpenedMapsProps = {
+  queryData: QueryData;
+};
+
+export type MapSizeAndModelId = Pick<MapData, 'modelId' | 'size'>;
+export type InitMapSizeAndModelIdActionPayload = MapSizeAndModelId;
+export type InitMapSizeAndModelIdParams = {
+  queryData: QueryData;
+};
+
+export type InitMapPositionActionPayload = Position;
+export type InitMapPositionParams = {
+  queryData: QueryData;
+};
+
+export type InitMapBackgroundActionPayload = number;
+export type InitMapBackgroundParams = {
+  queryData: QueryData;
+};
diff --git a/src/redux/map/middleware/checkIfIsMapUpdateActionValid.test.ts b/src/redux/map/middleware/checkIfIsMapUpdateActionValid.test.ts
index aa889249020931981df2631afd7550950ced7dbf..5580c0242b1e669dddc051a2f0f181a0e0ebe8c4 100644
--- a/src/redux/map/middleware/checkIfIsMapUpdateActionValid.test.ts
+++ b/src/redux/map/middleware/checkIfIsMapUpdateActionValid.test.ts
@@ -1,6 +1,10 @@
 import { RootState } from '@/redux/store';
 import { Loading } from '@/types/loadingState';
-import { MAP_DATA_INITIAL_STATE, MIDDLEWARE_ALLOWED_ACTIONS } from '../map.constants';
+import {
+  MAP_DATA_INITIAL_STATE,
+  MIDDLEWARE_ALLOWED_ACTIONS,
+  OPENED_MAPS_INITIAL_STATE,
+} from '../map.constants';
 import { SetMapDataAction } from '../map.types';
 import { checkIfIsMapUpdateActionValid } from './checkIfIsMapUpdateActionValid';
 
@@ -12,6 +16,7 @@ const state: Pick<RootState, 'map'> = {
     },
     loading: 'idle' as Loading,
     error: { name: '', message: '' },
+    openedMaps: OPENED_MAPS_INITIAL_STATE,
   },
 };
 
diff --git a/src/redux/map/middleware/map.middleware.test.ts b/src/redux/map/middleware/map.middleware.test.ts
index 3359b92a548c0bee5ec6e40c7a651f163b12d3dd..11015648425d5752f83f22dd282a2e089a5e7871 100644
--- a/src/redux/map/middleware/map.middleware.test.ts
+++ b/src/redux/map/middleware/map.middleware.test.ts
@@ -3,7 +3,11 @@ import { modelsFixture } from '@/models/fixtures/modelsFixture';
 import { Loading } from '@/types/loadingState';
 import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { Action } from '@reduxjs/toolkit';
-import { MAP_DATA_INITIAL_STATE, MIDDLEWARE_ALLOWED_ACTIONS } from '../map.constants';
+import {
+  MAP_DATA_INITIAL_STATE,
+  MIDDLEWARE_ALLOWED_ACTIONS,
+  OPENED_MAPS_INITIAL_STATE,
+} from '../map.constants';
 import * as mapSlice from '../map.slice';
 import * as checkIfIsMapUpdateActionValid from './checkIfIsMapUpdateActionValid';
 import * as getUpdatedModel from './getUpdatedModel';
@@ -58,6 +62,7 @@ const { store } = getReduxWrapperWithStore({
       ...MAP_DATA_INITIAL_STATE,
       modelId: modelsFixture[0].idObject,
     },
+    openedMaps: OPENED_MAPS_INITIAL_STATE,
   },
   models: {
     ...defaultSliceState,
diff --git a/src/redux/map/middleware/map.middleware.ts b/src/redux/map/middleware/map.middleware.ts
index f3e12654c64b70720198f86e086789f29136353e..5658c14519d6d650b3c70b52abf90f2252fd1219 100644
--- a/src/redux/map/middleware/map.middleware.ts
+++ b/src/redux/map/middleware/map.middleware.ts
@@ -1,23 +1,22 @@
 import { currentBackgroundSelector } from '@/redux/backgrounds/background.selectors';
-import type { AppDispatch, AppListenerEffectAPI, AppStartListening } from '@/redux/store';
-import { GetUpdatedMapDataResult, getUpdatedMapData } from '@/utils/map/getUpdatedMapData';
-import { Action, createListenerMiddleware } from '@reduxjs/toolkit';
-import { setMapData, setMapPosition } from '../map.slice';
+import type { AppListenerEffectAPI, AppStartListening } from '@/redux/store';
+import { getUpdatedMapData } from '@/utils/map/getUpdatedMapData';
+import { Action, createListenerMiddleware, isAnyOf } from '@reduxjs/toolkit';
+import {
+  openMapAndSetActive,
+  setActiveMap,
+  setMapData,
+  setMapPosition,
+  closeMapAndSetMainMapActive,
+} from '../map.slice';
 import { checkIfIsMapUpdateActionValid } from './checkIfIsMapUpdateActionValid';
 import { getUpdatedModel } from './getUpdatedModel';
+import { mapOpenedMapPositionByIdSelector } from '../map.selectors';
 
 export const mapListenerMiddleware = createListenerMiddleware();
 
 const startListening = mapListenerMiddleware.startListening as AppStartListening;
 
-/* prettier-ignore */
-export const dispatchMapDataWithPosition =
-  (updatedMapData: GetUpdatedMapDataResult) =>
-    (dispatch: AppDispatch): void => {
-      dispatch(setMapData(updatedMapData));
-      dispatch(setMapPosition(updatedMapData));
-    };
-
 export const mapDataMiddlewareListener = async (
   action: Action,
   { getOriginalState, dispatch }: AppListenerEffectAPI,
@@ -31,12 +30,18 @@ export const mapDataMiddlewareListener = async (
   }
 
   const background = currentBackgroundSelector(state);
-  const updatedMapData = getUpdatedMapData({ model: updatedModel, background });
+  const modelId = updatedModel.idObject;
+  const lastPosition = mapOpenedMapPositionByIdSelector(state, modelId);
+  const updatedMapData = getUpdatedMapData({
+    model: updatedModel,
+    position: { initial: lastPosition, last: lastPosition },
+    background,
+  });
   dispatch(setMapData(updatedMapData));
   dispatch(setMapPosition(updatedMapData));
 };
 
 startListening({
-  type: 'map/setMapData',
+  matcher: isAnyOf(setMapData, setActiveMap, openMapAndSetActive, closeMapAndSetMainMapActive),
   effect: mapDataMiddlewareListener,
 });
diff --git a/src/redux/mirnas/mirnas.mock.ts b/src/redux/mirnas/mirnas.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..233c3558ef20fe6eb8a1e607c64b8940ad8aaac7
--- /dev/null
+++ b/src/redux/mirnas/mirnas.mock.ts
@@ -0,0 +1,8 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { MirnasState } from './mirnas.types';
+
+export const MIRNAS_INITIAL_STATE_MOCK: MirnasState = {
+  data: undefined,
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
diff --git a/src/redux/models/models.mock.ts b/src/redux/models/models.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e45763d82516d7ff30c12ee7512a8da5f2378cdf
--- /dev/null
+++ b/src/redux/models/models.mock.ts
@@ -0,0 +1,8 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { ModelsState } from './models.types';
+
+export const MODELS_INITIAL_STATE_MOCK: ModelsState = {
+  data: [],
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
diff --git a/src/redux/models/models.selectors.ts b/src/redux/models/models.selectors.ts
index 071b06826fa06e98e6e71ef6a528032f1caa0e38..70a6671c5bb2f6aef66ac96c76c9f447a12e314b 100644
--- a/src/redux/models/models.selectors.ts
+++ b/src/redux/models/models.selectors.ts
@@ -1,6 +1,7 @@
 import { rootSelector } from '@/redux/root/root.selectors';
 import { createSelector } from '@reduxjs/toolkit';
 import { mapDataSelector } from '../map/map.selectors';
+import { MODEL_ID_DEFAULT } from '../map/map.constants';
 
 export const modelsSelector = createSelector(rootSelector, state => state.models);
 
@@ -15,5 +16,12 @@ export const currentModelSelector = createSelector(
 export const currentModelIdSelector = createSelector(
   currentModelSelector,
   // eslint-disable-next-line no-magic-numbers
-  model => model?.idObject || 0,
+  model => model?.idObject || MODEL_ID_DEFAULT,
 );
+export const modelByIdSelector = createSelector(
+  [modelsSelector, (_state, modelId: number): number => modelId],
+  (models, modelId) => (models?.data || []).find(({ idObject }) => idObject === modelId),
+);
+
+const MAIN_MAP = 0;
+export const mainMapModelSelector = createSelector(modelsDataSelector, models => models[MAIN_MAP]);
diff --git a/src/redux/overlays/overlays.mock.ts b/src/redux/overlays/overlays.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1a8037b6ba6e1ca5a7d096a71ae79a6f3c388fd5
--- /dev/null
+++ b/src/redux/overlays/overlays.mock.ts
@@ -0,0 +1,8 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { OverlaysState } from './overlays.types';
+
+export const OVERLAYS_INITIAL_STATE_MOCK: OverlaysState = {
+  data: [],
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
diff --git a/src/redux/project/project.mock.ts b/src/redux/project/project.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..036d26346ca92cb0a8108cb83b7c7584db660381
--- /dev/null
+++ b/src/redux/project/project.mock.ts
@@ -0,0 +1,8 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { ProjectState } from './project.types';
+
+export const PROJECT_STATE_INITIAL_MOCK: ProjectState = {
+  data: undefined,
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
diff --git a/src/redux/reactions/reactions.mock.ts b/src/redux/reactions/reactions.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f8d9614b5a568fb8af107b76bff3180766d31c46
--- /dev/null
+++ b/src/redux/reactions/reactions.mock.ts
@@ -0,0 +1,8 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { ReactionsState } from './reactions.types';
+
+export const REACTIONS_STATE_INITIAL_MOCK: ReactionsState = {
+  data: [],
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
diff --git a/src/redux/root/init.selectors.ts b/src/redux/root/init.selectors.ts
index 5095956a5633679600d67a86d458ecffb7227ac2..67cdfa08df4a16ab64f183a41c1c741ccc62bb74 100644
--- a/src/redux/root/init.selectors.ts
+++ b/src/redux/root/init.selectors.ts
@@ -13,7 +13,15 @@ export const initDataLoadingInitialized = createSelector(
   (...selectors) => selectors.every(selector => selector.loading !== 'idle'),
 );
 
-export const initDataLoadingFinished = createSelector(
+export const initDataLoadingFinishedSelector = createSelector(
+  projectSelector,
+  backgroundsSelector,
+  modelsSelector,
+  overlaysSelector,
+  (...selectors) => selectors.every(selector => selector.loading === 'succeeded'),
+);
+
+export const initDataAndMapLoadingFinished = createSelector(
   projectSelector,
   backgroundsSelector,
   modelsSelector,
diff --git a/src/redux/root/init.thunks.ts b/src/redux/root/init.thunks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c91e96efa82dbbd6ab9d2dd628fb4ff5f8770728
--- /dev/null
+++ b/src/redux/root/init.thunks.ts
@@ -0,0 +1,40 @@
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { PROJECT_ID } from '@/constants';
+import { AppDispatch } from '@/redux/store';
+import { QueryData } from '@/types/query';
+import { getAllBackgroundsByProjectId } from '../backgrounds/backgrounds.thunks';
+import { getAllPublicOverlaysByProjectId } from '../overlays/overlays.thunks';
+import { getModels } from '../models/models.thunks';
+import { getProjectById } from '../project/project.thunks';
+import {
+  initMapBackground,
+  initMapPosition,
+  initMapSizeAndModelId,
+  initOpenedMaps,
+} from '../map/map.thunks';
+
+interface InitializeAppParams {
+  queryData: QueryData;
+}
+
+export const fetchInitialAppData = createAsyncThunk<
+  void,
+  InitializeAppParams,
+  { dispatch: AppDispatch }
+>('appInit/fetchInitialAppData', async ({ queryData }, { dispatch }): Promise<void> => {
+  /** Fetch all data required for renderin map */
+  await Promise.all([
+    dispatch(getProjectById(PROJECT_ID)),
+    dispatch(getAllBackgroundsByProjectId(PROJECT_ID)),
+    dispatch(getAllPublicOverlaysByProjectId(PROJECT_ID)),
+    dispatch(getModels()),
+  ]);
+  /**  Set map properties to allow rendering. If map params (modelId,backgroundId,position) are not provided in query -> it will be set to map default */
+  await Promise.all([
+    dispatch(initMapSizeAndModelId({ queryData })),
+    dispatch(initMapPosition({ queryData })),
+    dispatch(initMapBackground({ queryData })),
+  ]);
+  /** Create tabs for maps / submaps */
+  dispatch(initOpenedMaps({ queryData }));
+});
diff --git a/src/redux/root/root.fixtures.ts b/src/redux/root/root.fixtures.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b310aceb4dd5c6ee53311b332ca00a6ef9b7963c
--- /dev/null
+++ b/src/redux/root/root.fixtures.ts
@@ -0,0 +1,28 @@
+import { BACKGROUND_INITIAL_STATE_MOCK } from '../backgrounds/background.mock';
+import { BIOENTITY_INITIAL_STATE_MOCK } from '../bioEntity/bioEntity.mock';
+import { CHEMICALS_INITIAL_STATE_MOCK } from '../chemicals/chemicals.mock';
+import { initialStateFixture as drawerInitialStateMock } from '../drawer/drawerFixture';
+import { DRUGS_INITIAL_STATE_MOCK } from '../drugs/drugs.mock';
+import { initialMapStateFixture } from '../map/map.fixtures';
+import { MIRNAS_INITIAL_STATE_MOCK } from '../mirnas/mirnas.mock';
+import { MODELS_INITIAL_STATE_MOCK } from '../models/models.mock';
+import { OVERLAYS_INITIAL_STATE_MOCK } from '../overlays/overlays.mock';
+import { PROJECT_STATE_INITIAL_MOCK } from '../project/project.mock';
+import { REACTIONS_STATE_INITIAL_MOCK } from '../reactions/reactions.mock';
+import { SEARCH_STATE_INITIAL_MOCK } from '../search/search.mock';
+import { RootState } from '../store';
+
+export const INITIAL_STORE_STATE_MOCK: RootState = {
+  search: SEARCH_STATE_INITIAL_MOCK,
+  project: PROJECT_STATE_INITIAL_MOCK,
+  drugs: DRUGS_INITIAL_STATE_MOCK,
+  mirnas: MIRNAS_INITIAL_STATE_MOCK,
+  chemicals: CHEMICALS_INITIAL_STATE_MOCK,
+  models: MODELS_INITIAL_STATE_MOCK,
+  bioEntity: BIOENTITY_INITIAL_STATE_MOCK,
+  backgrounds: BACKGROUND_INITIAL_STATE_MOCK,
+  drawer: drawerInitialStateMock,
+  map: initialMapStateFixture,
+  overlays: OVERLAYS_INITIAL_STATE_MOCK,
+  reactions: REACTIONS_STATE_INITIAL_MOCK,
+};
diff --git a/src/redux/search/search.mock.ts b/src/redux/search/search.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..83aa9e6ce6b0602f9027f54ae9c29c36dfa1d40a
--- /dev/null
+++ b/src/redux/search/search.mock.ts
@@ -0,0 +1,6 @@
+import { SearchState } from './search.types';
+
+export const SEARCH_STATE_INITIAL_MOCK: SearchState = {
+  searchValue: '',
+  loading: 'idle',
+};
diff --git a/src/types/query.ts b/src/types/query.ts
index a715a34a3397f9f4bb7b2a3eaa7e82657d7d1463..bd9cb48cdd9983d0bde3e12c4b0bb63e2cceb6f3 100644
--- a/src/types/query.ts
+++ b/src/types/query.ts
@@ -13,3 +13,11 @@ export interface QueryDataParams {
   y?: number;
   z?: number;
 }
+
+export interface QueryDataRouterParams {
+  modelId?: string;
+  backgroundId?: string;
+  x?: string;
+  y?: string;
+  z?: string;
+}
diff --git a/src/utils/canvas/getCanvas.ts b/src/utils/canvas/getCanvas.ts
new file mode 100644
index 0000000000000000000000000000000000000000..390bba041a91febfdbf7945eb97c0be8ac4bdb80
--- /dev/null
+++ b/src/utils/canvas/getCanvas.ts
@@ -0,0 +1,12 @@
+export const getCanvas = ({
+  width,
+  height,
+}: {
+  width: number;
+  height: number;
+}): HTMLCanvasElement => {
+  const canvas = document.createElement('canvas');
+  canvas.width = width;
+  canvas.height = height;
+  return canvas;
+};
diff --git a/src/utils/canvas/getFontSizeToFit.ts b/src/utils/canvas/getFontSizeToFit.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c74b4b0540cdb103bc4b1b79811250f76e33fac9
--- /dev/null
+++ b/src/utils/canvas/getFontSizeToFit.ts
@@ -0,0 +1,9 @@
+export const getFontSizeToFit = (
+  ctx: CanvasRenderingContext2D,
+  text: string,
+  fontFace: string,
+  maxWidth: number,
+): number => {
+  ctx.font = `1px ${fontFace}`;
+  return maxWidth / ctx.measureText(text).width;
+};
diff --git a/src/utils/initialize/useInitializeStore.ts b/src/utils/initialize/useInitializeStore.ts
index 207bd0ca713ab57733715d36e24c72aac3702b2d..9722dd6173ea1fe82164f422f0b7d6dc106a22de 100644
--- a/src/utils/initialize/useInitializeStore.ts
+++ b/src/utils/initialize/useInitializeStore.ts
@@ -1,43 +1,30 @@
-import { PROJECT_ID } from '@/constants';
-import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
-import { initMapData, initMapPosition } from '@/redux/map/map.thunks';
-import { getProjectById } from '@/redux/project/project.thunks';
-import { initDataLoadingInitialized } from '@/redux/root/init.selectors';
-import { AppDispatch } from '@/redux/store';
-import { QueryData } from '@/types/query';
 import { useRouter } from 'next/router';
-import { useEffect } from 'react';
-import { useSelector } from 'react-redux';
-import { getQueryData } from '../query-manager/getQueryData';
-
-interface GetInitStoreDataArgs {
-  queryData: QueryData;
-}
+import { useEffect, useMemo } from 'react';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import {
+  initDataLoadingFinishedSelector,
+  initDataLoadingInitialized,
+} from '@/redux/root/init.selectors';
+import { fetchInitialAppData } from '@/redux/root/init.thunks';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { parseQueryToTypes } from '../parseQueryToTypes';
 
-/* prettier-ignore */
-export const getInitStoreData =
-  ({ queryData }: GetInitStoreDataArgs) =>
-    (dispatch: AppDispatch): void => {
-      dispatch(getProjectById(PROJECT_ID));
-      dispatch(initMapData({ queryData }));
-      dispatch(initMapPosition({ queryData }));
-    };
+/**
+ * 1. Initialise all required data before app starts: Project info, available Backgrounds, available Overlays, available Models (maps,submaps)
+ * 2. Based on that set required map data to correctly display view. If query params are available -> use them to set map data
+ */
 
 export const useInitializeStore = (): void => {
   const dispatch = useAppDispatch();
-  const isInitialized = useSelector(initDataLoadingInitialized);
+  const isInitialized = useAppSelector(initDataLoadingInitialized);
+  const isInitDataLoadingFinished = useAppSelector(initDataLoadingFinishedSelector);
   const { query, isReady: isRouterReady } = useRouter();
+  const isQueryReady = useMemo(() => query && isRouterReady, [query, isRouterReady]);
 
   useEffect(() => {
-    const isQueryReady = query && isRouterReady;
     if (isInitialized || !isQueryReady) {
       return;
     }
-
-    dispatch(
-      getInitStoreData({
-        queryData: getQueryData(query),
-      }),
-    );
-  }, [dispatch, query, isInitialized, isRouterReady]);
+    dispatch(fetchInitialAppData({ queryData: parseQueryToTypes(query) }));
+  }, [dispatch, isInitialized, query, isQueryReady, isInitDataLoadingFinished]);
 };
diff --git a/src/utils/map/getUpdatedMapData.ts b/src/utils/map/getUpdatedMapData.ts
index dbfcf755181fbc08a8d066d71a22b66a2afaeacd..6baeeae09b8f1693b0605e6aafd4a9ba7ca460ec 100644
--- a/src/utils/map/getUpdatedMapData.ts
+++ b/src/utils/map/getUpdatedMapData.ts
@@ -1,10 +1,6 @@
 import { DEFAULT_ZOOM } from '@/constants/map';
 import { MAP_DATA_INITIAL_STATE } from '@/redux/map/map.constants';
-import {
-  MapData,
-  SetMapDataActionPayload,
-  SetMapPositionDataActionPayload,
-} from '@/redux/map/map.types';
+import { GetUpdatedMapDataResult, MapData } from '@/redux/map/map.types';
 import { MapBackground, MapModel } from '@/types/models';
 import { DeepPartial } from '@reduxjs/toolkit';
 import { getPointMerged } from '../object/getPointMerged';
@@ -15,8 +11,6 @@ interface GetUpdatedMapDataArgs {
   background?: MapBackground;
 }
 
-export type GetUpdatedMapDataResult = SetMapDataActionPayload & SetMapPositionDataActionPayload;
-
 const HALF = 2;
 
 export const getUpdatedMapData = ({
diff --git a/src/utils/parseQueryToTypes.test.ts b/src/utils/parseQueryToTypes.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8151e0c92e2ff939d747db75b3bc68d62f2ec2e0
--- /dev/null
+++ b/src/utils/parseQueryToTypes.test.ts
@@ -0,0 +1,28 @@
+import { parseQueryToTypes } from './parseQueryToTypes';
+
+describe('parseQueryToTypes', () => {
+  it('should return valid data', () => {
+    expect({}).toEqual({});
+
+    expect(parseQueryToTypes({ modelId: '666' })).toEqual({
+      modelId: 666,
+      backgroundId: undefined,
+      initialPosition: { x: undefined, y: undefined, z: undefined },
+    });
+    expect(parseQueryToTypes({ x: '2137' })).toEqual({
+      modelId: undefined,
+      backgroundId: undefined,
+      initialPosition: { x: 2137, y: undefined, z: undefined },
+    });
+    expect(parseQueryToTypes({ y: '1372' })).toEqual({
+      modelId: undefined,
+      backgroundId: undefined,
+      initialPosition: { x: undefined, y: 1372, z: undefined },
+    });
+    expect(parseQueryToTypes({ z: '3721' })).toEqual({
+      modelId: undefined,
+      backgroundId: undefined,
+      initialPosition: { x: undefined, y: undefined, z: 3721 },
+    });
+  });
+});
diff --git a/src/utils/parseQueryToTypes.ts b/src/utils/parseQueryToTypes.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d1b3f297cb084fdc71c10e98798df7edbc5c084e
--- /dev/null
+++ b/src/utils/parseQueryToTypes.ts
@@ -0,0 +1,11 @@
+import { QueryData, QueryDataRouterParams } from '@/types/query';
+
+export const parseQueryToTypes = (query: QueryDataRouterParams): QueryData => ({
+  modelId: Number(query.modelId) || undefined,
+  backgroundId: Number(query.backgroundId) || undefined,
+  initialPosition: {
+    x: Number(query.x) || undefined,
+    y: Number(query.y) || undefined,
+    z: Number(query.z) || undefined,
+  },
+});
diff --git a/src/utils/query-manager/useReduxBusQueryManager.test.ts b/src/utils/query-manager/useReduxBusQueryManager.test.ts
index 2963f999eaf62520de711a7684963b46df83f3e7..dc4bc4b6595a1966de2cabb7c3a54143e033ef42 100644
--- a/src/utils/query-manager/useReduxBusQueryManager.test.ts
+++ b/src/utils/query-manager/useReduxBusQueryManager.test.ts
@@ -1,4 +1,4 @@
-import { MAP_DATA_INITIAL_STATE } from '@/redux/map/map.constants';
+import { MAP_DATA_INITIAL_STATE, OPENED_MAPS_INITIAL_STATE } from '@/redux/map/map.constants';
 import { Loading } from '@/types/loadingState';
 import { renderHook, waitFor } from '@testing-library/react';
 import mockRouter from 'next-router-mock';
@@ -10,7 +10,7 @@ describe('useReduxBusQueryManager - util', () => {
     const { Wrapper } = getReduxWrapperWithStore();
 
     jest.mock('./../../redux/root/init.selectors', () => ({
-      initDataLoadingFinished: jest.fn().mockImplementation(() => false),
+      initDataAndMapLoadingFinished: jest.fn().mockImplementation(() => false),
     }));
 
     it('should not update query', () => {
@@ -51,6 +51,7 @@ describe('useReduxBusQueryManager - util', () => {
             },
           },
         },
+        openedMaps: OPENED_MAPS_INITIAL_STATE,
       },
       backgrounds: loadedDataMock,
       models: loadedDataMock,
diff --git a/src/utils/query-manager/useReduxBusQueryManager.ts b/src/utils/query-manager/useReduxBusQueryManager.ts
index 4ad04c417f2044f420782544930cffada60388b9..80d277dd03a6954af2085dbc98fe7c75cf169663 100644
--- a/src/utils/query-manager/useReduxBusQueryManager.ts
+++ b/src/utils/query-manager/useReduxBusQueryManager.ts
@@ -2,12 +2,12 @@ import { queryDataParamsSelector } from '@/redux/root/query.selectors';
 import { useRouter } from 'next/router';
 import { useCallback, useEffect } from 'react';
 import { useSelector } from 'react-redux';
-import { initDataLoadingFinished } from '../../redux/root/init.selectors';
+import { initDataAndMapLoadingFinished } from '../../redux/root/init.selectors';
 
 export const useReduxBusQueryManager = (): void => {
   const router = useRouter();
   const queryData = useSelector(queryDataParamsSelector);
-  const isDataLoaded = useSelector(initDataLoadingFinished);
+  const isDataLoaded = useSelector(initDataAndMapLoadingFinished);
 
   const handleChangeQuery = useCallback(
     () =>
diff --git a/yarn.lock b/yarn.lock
index 8c7c992b13f50fb1b7aea03170a5358cf03dfb1c..e5bd596f461837f6b40744e75a28af01684831e7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -847,9 +847,9 @@
   "resolved" "https://registry.npmjs.org/@next/font/-/font-13.5.4.tgz"
   "version" "13.5.4"
 
-"@next/swc-darwin-arm64@13.4.19":
-  "integrity" "sha512-vv1qrjXeGbuF2mOkhkdxMDtv9np7W4mcBtaDnHU+yJG+bBwa6rYsYSCI/9Xm5+TuF5SbZbrWO6G1NfTh1TMjvQ=="
-  "resolved" "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.19.tgz"
+"@next/swc-darwin-x64@13.4.19":
+  "integrity" "sha512-jyzO6wwYhx6F+7gD8ddZfuqO4TtpJdw3wyOduR4fxTUCm3aLw7YmHGYNjS0xRSYGAkLpBkH1E0RcelyId6lNsw=="
+  "resolved" "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.19.tgz"
   "version" "13.4.19"
 
 "@next/swc-darwin-x64@13.4.19":