From 24e590fa04435742310982fec3d7483ce669da6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrian=20Or=C5=82=C3=B3w?= <adrian.orlow@fishbrain.com>
Date: Mon, 8 Jan 2024 16:58:35 +0100
Subject: [PATCH] Merge remote-tracking branch 'origin/development' into
 MIN-169-display-legend

---
 .eslintrc.json                                |   9 +-
 package-lock.json                             |  59 +++++
 package.json                                  |   1 +
 setupTests.ts                                 |   4 +
 .../Modal/LoginModal/LoginModal.component.tsx |   9 +-
 .../BioEntityDrawer.component.tsx             |   8 +-
 .../Map/Drawer/Drawer.component.tsx           |   2 +
 .../Annotations.component.test.tsx            | 119 +++++++++
 .../Annotations/Annotations.component.tsx     |  40 +++
 .../Drawer/ExportDrawer/Annotations/index.ts  |   1 +
 .../CheckboxFilter.component.test.tsx         | 109 ++++++++
 .../CheckboxFilter.component.tsx              | 105 ++++++++
 .../ExportDrawer/CheckboxFilter/index.ts      |   1 +
 .../CollapsibleSection.component.test.tsx     |  37 +++
 .../CollapsibleSection.component.tsx          |  26 ++
 .../ExportDrawer/CollapsibleSection/index.ts  |   1 +
 .../Annotations.component.test.tsx            | 122 +++++++++
 .../Annotations/Annotations.component.tsx     |  27 ++
 .../Elements/Annotations/index.ts             |   1 +
 .../Columns/Columns.component.test.tsx        |  26 ++
 .../Elements/Columns/Columns.component.tsx    |   9 +
 .../Elements/Columns/Columns.constants.tsx    |  86 +++++++
 .../ExportDrawer/Elements/Columns/index.ts    |   1 +
 .../Elements/Elements.component.tsx           |  13 +
 .../Elements/Types/Types.component.test.tsx   |  29 +++
 .../Elements/Types/Types.component.tsx        |  16 ++
 .../Elements/Types/Types.utils.test.ts        |  36 +++
 .../Elements/Types/Types.utils.ts             |  35 +++
 .../ExportDrawer/Elements/Types/index.ts      |   1 +
 .../Map/Drawer/ExportDrawer/Elements/index.ts |   1 +
 .../ExportDrawer.component.test.tsx           |  70 +++++
 .../ExportDrawer/ExportDrawer.component.tsx   |  24 ++
 .../TabButton/TabButton.component.test.tsx    |  37 +++
 .../TabButton/TabButton.component.tsx         |  22 ++
 .../Drawer/ExportDrawer/TabButton/index.ts    |   1 +
 .../TabNavigator.component.test.tsx           |  36 +++
 .../TabNavigator/TabNavigator.component.tsx   |  21 ++
 .../TabNavigator/TabNavigator.constants.ts    |   5 +
 .../TabNavigator/TabNavigator.types.ts        |   3 +
 .../Drawer/ExportDrawer/TabNavigator/index.ts |   1 +
 .../Map/Drawer/ExportDrawer/index.ts          |   1 +
 .../OverlaysDrawer.component.tsx              |  21 +-
 .../FileUpload/FileUpload.component.test.tsx  |  42 +++
 .../FileUpload/FileUpload.component.tsx       |  62 +++++
 .../UserOverlayForm/FileUpload/index.ts       |   1 +
 .../OverlaySelector.component.test.tsx        |  48 ++++
 .../OverlaySelector.component.tsx             |  84 ++++++
 .../UserOverlayForm/OverlaySelector/index.ts  |   1 +
 .../UserOverlayForm.component.test.tsx        | 240 ++++++++++++++++++
 .../UserOverlayForm.component.tsx             | 121 +++++++++
 .../UserOverlayForm.constants.ts              |  22 ++
 .../UserOverlayForm/UserOverlayForm.types.ts  |   1 +
 .../UserOverlayForm.utils.test.ts             |  29 +++
 .../UserOverlayForm/UserOverlayForm.utils.ts  |  27 ++
 .../hooks/useUserOverlayForm.test.ts          |  59 +++++
 .../hooks/useUserOverlayForm.ts               | 143 +++++++++++
 .../OverlaysDrawer/UserOverlayForm/index.ts   |   1 +
 .../UserOverlays.component.test.tsx           |  83 ++++++
 .../UserOverlays/UserOverlays.component.tsx   |  24 +-
 .../BioEntitiesAccordion.component.test.tsx   |   6 +-
 .../ResultsList.component.test.tsx            |   3 +
 .../SearchDrawerWrapper.component.test.tsx    |   6 +
 .../createOverlayGeometryFeature.ts           |  12 +-
 .../overlaysLayer/getOverlayFeatures.ts       |  30 ++-
 .../getPolygonLatitudeCoordinates.test.ts     |  40 +++
 .../getPolygonLatitudeCoordinates.ts          |  26 ++
 .../overlaysLayer/useOlMapOverlaysLayer.ts    |  35 ++-
 .../reactionsLayer/useOlMapReactionsLayer.ts  |   3 +-
 src/models/bioEntitySchema.ts                 |  11 +-
 src/models/configurationSchema.ts             | 105 ++++++++
 src/models/fixtures/overlaysFixture.ts        |  18 +-
 src/models/fixtures/statisticsFixture.ts      |   8 +
 src/models/mapOverlay.ts                      |  23 ++
 src/models/statisticsSchema.ts                |   7 +
 src/redux/apiPath.ts                          |   5 +
 .../configuration/configuration.adapter.ts    |  12 +-
 src/redux/configuration/configuration.mock.ts |  38 ++-
 .../configuration/configuration.reducers.ts   |  26 +-
 .../configuration/configuration.selectors.ts  |  23 +-
 .../configuration/configuration.slice.ts      |   3 +-
 .../configuration/configuration.thunks.ts     |  14 +-
 .../configuration/configuration.types.ts      |   4 +
 src/redux/drawer/drawer.constants.ts          |   3 +
 src/redux/drawer/drawer.reducers.ts           |   7 +
 src/redux/drawer/drawer.selectors.ts          |  10 +
 src/redux/drawer/drawer.slice.ts              |   3 +
 src/redux/drawer/drawer.types.ts              |   5 +
 src/redux/drawer/drawerFixture.ts             |  49 ++++
 .../overlayBioEntity.selector.ts              |  32 ++-
 .../overlayBioEntity.thunk.ts                 |  18 ++
 .../overlayBioEntity.utils.test.ts            |  64 +++++
 .../overlayBioEntity.utils.ts                 |  43 ++++
 src/redux/overlays/overlays.constants.ts      |   2 +
 src/redux/overlays/overlays.mock.ts           |  17 ++
 src/redux/overlays/overlays.reducers.test.ts  |  72 +++++-
 src/redux/overlays/overlays.reducers.ts       |  15 +-
 src/redux/overlays/overlays.selectors.ts      |   9 +
 src/redux/overlays/overlays.slice.ts          |   7 +-
 src/redux/overlays/overlays.thunks.ts         | 144 ++++++++++-
 src/redux/overlays/overlays.types.ts          |  10 +-
 src/redux/project/project.selectors.ts        |   5 +
 src/redux/root/init.thunks.ts                 |  15 +-
 src/redux/root/query.selectors.ts             |  28 +-
 src/redux/root/root.fixtures.ts               |   2 +
 src/redux/statistics/statistics.mock.ts       |   8 +
 .../statistics/statistics.reducers.test.ts    |  70 +++++
 src/redux/statistics/statistics.reducers.ts   |  18 ++
 src/redux/statistics/statistics.selectors.ts  |  16 ++
 src/redux/statistics/statistics.slice.ts      |  20 ++
 src/redux/statistics/statistics.thunks.ts     |  17 ++
 src/redux/statistics/statistics.types.ts      |   4 +
 src/redux/store.ts                            |   2 +
 src/shared/Input/Input.component.test.tsx     |  70 +++++
 src/shared/Input/Input.component.tsx          |  33 +++
 src/shared/Input/index.ts                     |   1 +
 .../Textarea/Textarea.component.test.tsx      |  53 ++++
 src/shared/Textarea/Textarea.component.tsx    |  22 ++
 src/shared/Textarea/index.ts                  |   1 +
 src/types/OLrendering.ts                      |   4 +
 src/types/models.ts                           |  14 +-
 src/types/query.ts                            |   3 +
 src/utils/number/roundToTwoDigits.test.ts     |  32 +++
 src/utils/number/roundToTwoDigits.ts          |   2 +
 src/utils/parseQueryToTypes.test.ts           |  16 ++
 src/utils/parseQueryToTypes.ts                |   1 +
 .../useReduxBusQueryManager.test.ts           |   4 +
 126 files changed, 3502 insertions(+), 91 deletions(-)
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.test.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Annotations/index.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.test.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/CheckboxFilter/index.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/CollapsibleSection/CollapsibleSection.component.test.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/CollapsibleSection/CollapsibleSection.component.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/CollapsibleSection/index.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.test.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Annotations/index.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.test.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.constants.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Columns/index.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.test.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.test.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/Types/index.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/Elements/index.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.test.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/TabButton/TabButton.component.test.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/TabButton/TabButton.component.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/TabButton/index.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.component.test.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.component.tsx
 create mode 100644 src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.constants.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.types.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/TabNavigator/index.ts
 create mode 100644 src/components/Map/Drawer/ExportDrawer/index.ts
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/FileUpload.component.test.tsx
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/FileUpload.component.tsx
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/index.ts
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/OverlaySelector.component.test.tsx
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/OverlaySelector.component.tsx
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/index.ts
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.tsx
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.constants.ts
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.types.ts
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.utils.test.ts
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.utils.ts
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/hooks/useUserOverlayForm.test.ts
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/hooks/useUserOverlayForm.ts
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/index.ts
 create mode 100644 src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.test.tsx
 create mode 100644 src/components/Map/MapViewer/utils/config/overlaysLayer/getPolygonLatitudeCoordinates.test.ts
 create mode 100644 src/components/Map/MapViewer/utils/config/overlaysLayer/getPolygonLatitudeCoordinates.ts
 create mode 100644 src/models/configurationSchema.ts
 create mode 100644 src/models/fixtures/statisticsFixture.ts
 create mode 100644 src/models/statisticsSchema.ts
 create mode 100644 src/redux/configuration/configuration.types.ts
 create mode 100644 src/redux/overlayBioEntity/overlayBioEntity.utils.test.ts
 create mode 100644 src/redux/overlays/overlays.constants.ts
 create mode 100644 src/redux/statistics/statistics.mock.ts
 create mode 100644 src/redux/statistics/statistics.reducers.test.ts
 create mode 100644 src/redux/statistics/statistics.reducers.ts
 create mode 100644 src/redux/statistics/statistics.selectors.ts
 create mode 100644 src/redux/statistics/statistics.slice.ts
 create mode 100644 src/redux/statistics/statistics.thunks.ts
 create mode 100644 src/redux/statistics/statistics.types.ts
 create mode 100644 src/shared/Input/Input.component.test.tsx
 create mode 100644 src/shared/Input/Input.component.tsx
 create mode 100644 src/shared/Input/index.ts
 create mode 100644 src/shared/Textarea/Textarea.component.test.tsx
 create mode 100644 src/shared/Textarea/Textarea.component.tsx
 create mode 100644 src/shared/Textarea/index.ts
 create mode 100644 src/utils/number/roundToTwoDigits.test.ts
 create mode 100644 src/utils/number/roundToTwoDigits.ts

diff --git a/.eslintrc.json b/.eslintrc.json
index 3ed8a0da..8712576f 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -89,7 +89,14 @@
         "config": "./tailwind.config.ts"
       }
     ],
-    "prettier/prettier": "error"
+    "prettier/prettier": "error",
+    "jsx-a11y/label-has-associated-control": [
+      2,
+      {
+        "controlComponents": ["Input"],
+        "depth": 3
+      }
+    ]
   },
   "overrides": [
     {
diff --git a/package-lock.json b/package-lock.json
index 268c6f7e..4fb5b060 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27,6 +27,7 @@
         "react": "18.2.0",
         "react-accessible-accordion": "^5.0.0",
         "react-dom": "18.2.0",
+        "react-dropzone": "^14.2.3",
         "react-redux": "^8.1.2",
         "tailwind-merge": "^1.14.0",
         "tailwindcss": "3.3.3",
@@ -3050,6 +3051,14 @@
         "node": ">= 4.0.0"
       }
     },
+    "node_modules/attr-accept": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz",
+      "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/autoprefixer": {
       "version": "10.4.15",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz",
@@ -6349,6 +6358,17 @@
         "node": "^10.12.0 || >=12.0.0"
       }
     },
+    "node_modules/file-selector": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz",
+      "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      },
+      "engines": {
+        "node": ">= 12"
+      }
+    },
     "node_modules/fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -11359,6 +11379,22 @@
         "react": "^18.2.0"
       }
     },
+    "node_modules/react-dropzone": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz",
+      "integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==",
+      "dependencies": {
+        "attr-accept": "^2.2.2",
+        "file-selector": "^0.6.0",
+        "prop-types": "^15.8.1"
+      },
+      "engines": {
+        "node": ">= 10.13"
+      },
+      "peerDependencies": {
+        "react": ">= 16.8 || 18.0.0"
+      }
+    },
     "node_modules/react-is": {
       "version": "18.2.0",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
@@ -15894,6 +15930,11 @@
       "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
       "dev": true
     },
+    "attr-accept": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz",
+      "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg=="
+    },
     "autoprefixer": {
       "version": "10.4.15",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz",
@@ -18287,6 +18328,14 @@
         "flat-cache": "^3.0.4"
       }
     },
+    "file-selector": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz",
+      "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==",
+      "requires": {
+        "tslib": "^2.4.0"
+      }
+    },
     "fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -21770,6 +21819,16 @@
         "scheduler": "^0.23.0"
       }
     },
+    "react-dropzone": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz",
+      "integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==",
+      "requires": {
+        "attr-accept": "^2.2.2",
+        "file-selector": "^0.6.0",
+        "prop-types": "^15.8.1"
+      }
+    },
     "react-is": {
       "version": "18.2.0",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
diff --git a/package.json b/package.json
index deee43c5..081b8f16 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,7 @@
     "react": "18.2.0",
     "react-accessible-accordion": "^5.0.0",
     "react-dom": "18.2.0",
+    "react-dropzone": "^14.2.3",
     "react-redux": "^8.1.2",
     "tailwind-merge": "^1.14.0",
     "tailwindcss": "3.3.3",
diff --git a/setupTests.ts b/setupTests.ts
index e8c65391..1d944c81 100644
--- a/setupTests.ts
+++ b/setupTests.ts
@@ -10,6 +10,10 @@ global.ResizeObserver = jest.fn().mockImplementation(() => ({
 
 jest.mock('next/router', () => require('next-router-mock'));
 
+global.TextEncoder = jest.fn().mockImplementation(() => ({
+  encode: jest.fn(),
+}));
+
 const localStorageMock = (() => {
   let store: {
     [key: PropertyKey]: string;
diff --git a/src/components/FunctionalArea/Modal/LoginModal/LoginModal.component.tsx b/src/components/FunctionalArea/Modal/LoginModal/LoginModal.component.tsx
index 354b5337..40ac9436 100644
--- a/src/components/FunctionalArea/Modal/LoginModal/LoginModal.component.tsx
+++ b/src/components/FunctionalArea/Modal/LoginModal/LoginModal.component.tsx
@@ -3,6 +3,7 @@ import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { loadingUserSelector } from '@/redux/user/user.selectors';
 import { login } from '@/redux/user/user.thunks';
 import { Button } from '@/shared/Button';
+import { Input } from '@/shared/Input';
 import Link from 'next/link';
 import React from 'react';
 
@@ -27,26 +28,26 @@ export const LoginModal: React.FC = () => {
       <form onSubmit={handleSubmit}>
         <label className="mb-5 block text-sm font-semibold" htmlFor="login">
           Login:
-          <input
+          <Input
             type="text"
             name="login"
             id="login"
             placeholder="Your login here.."
             value={credentials.login}
             onChange={handleChange}
-            className="mt-2.5 h-10 w-full rounded-s border border-transparent bg-cultured px-2 py-2.5 text-sm font-medium text-font-400 outline-none  hover:border-greyscale-600 focus:border-greyscale-600"
+            className="mt-2.5 text-sm font-medium text-font-400"
           />
         </label>
         <label className="text-sm font-semibold" htmlFor="password">
           Password:
-          <input
+          <Input
             type="password"
             name="password"
             id="password"
             placeholder="Your password here.."
             value={credentials.password}
             onChange={handleChange}
-            className="mt-2.5 h-10 w-full rounded-s border border-transparent bg-cultured px-2 py-2.5 text-sm font-medium text-font-400 outline-none  hover:border-greyscale-600 focus:border-greyscale-600"
+            className="mt-2.5 text-sm font-medium text-font-400"
           />
         </label>
         <div className="mb-10 text-right">
diff --git a/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.tsx b/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.tsx
index 8bf424af..2d60852e 100644
--- a/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.tsx
+++ b/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.tsx
@@ -1,7 +1,7 @@
-import { DrawerHeading } from '@/shared/DrawerHeading';
-import { useAppSelector } from '@/redux/hooks/useAppSelector';
-import { searchedFromMapBioEntityElement } from '@/redux/bioEntity/bioEntity.selectors';
 import { ZERO } from '@/constants/common';
+import { searchedFromMapBioEntityElement } from '@/redux/bioEntity/bioEntity.selectors';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { DrawerHeading } from '@/shared/DrawerHeading';
 import { AnnotationItem } from './AnnotationItem';
 import { AssociatedSubmap } from './AssociatedSubmap';
 
@@ -26,7 +26,7 @@ export const BioEntityDrawer = (): React.ReactNode => {
       />
       <div className="flex flex-col gap-6 p-6">
         <div className="text-sm font-normal">
-          Compartment: <b className="font-semibold">{bioEntityData.compartment}</b>
+          Compartment: <b className="font-semibold">{bioEntityData.compartmentName}</b>
         </div>
         {bioEntityData.fullName && (
           <div className="text-sm font-normal">
diff --git a/src/components/Map/Drawer/Drawer.component.tsx b/src/components/Map/Drawer/Drawer.component.tsx
index ace83985..b55022ff 100644
--- a/src/components/Map/Drawer/Drawer.component.tsx
+++ b/src/components/Map/Drawer/Drawer.component.tsx
@@ -7,6 +7,7 @@ import { SearchDrawerWrapper as SearchDrawerContent } from './SearchDrawerWrappe
 import { SubmapsDrawer } from './SubmapsDrawer';
 import { OverlaysDrawer } from './OverlaysDrawer';
 import { BioEntityDrawer } from './BioEntityDrawer/BioEntityDrawer.component';
+import { ExportDrawer } from './ExportDrawer';
 
 export const Drawer = (): JSX.Element => {
   const { isOpen, drawerName } = useAppSelector(drawerSelector);
@@ -24,6 +25,7 @@ export const Drawer = (): JSX.Element => {
       {isOpen && drawerName === 'reaction' && <ReactionDrawer />}
       {isOpen && drawerName === 'overlays' && <OverlaysDrawer />}
       {isOpen && drawerName === 'bio-entity' && <BioEntityDrawer />}
+      {isOpen && drawerName === 'export' && <ExportDrawer />}
     </div>
   );
 };
diff --git a/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.test.tsx
new file mode 100644
index 00000000..df05c8e0
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.test.tsx
@@ -0,0 +1,119 @@
+import { render, screen, waitFor } from '@testing-library/react';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { StoreType } from '@/redux/store';
+import { statisticsFixture } from '@/models/fixtures/statisticsFixture';
+import { act } from 'react-dom/test-utils';
+import { Annotations } from './Annotations.component';
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <Annotations />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('Annotations - component', () => {
+  it('should display annotations checkboxes when fetching data is successful', async () => {
+    renderComponent({
+      statistics: {
+        data: {
+          ...statisticsFixture,
+          elementAnnotations: {
+            compartment: 1,
+            pathway: 0,
+          },
+        },
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    const navigationButton = screen.getByTestId('accordion-item-button');
+
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.getByText('Select annotations')).toBeInTheDocument();
+
+    await waitFor(() => {
+      expect(screen.getByTestId('checkbox-filter')).toBeInTheDocument();
+      expect(screen.getByLabelText('compartment')).toBeInTheDocument();
+      expect(screen.getByLabelText('search-input')).toBeInTheDocument();
+    });
+  });
+  it('should not display annotations checkboxes when fetching data fails', async () => {
+    renderComponent({
+      statistics: {
+        data: undefined,
+        loading: 'failed',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    expect(screen.getByText('Select annotations')).toBeInTheDocument();
+    const navigationButton = screen.getByTestId('accordion-item-button');
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument();
+  });
+  it('should not display annotations checkboxes when fetched data is empty object', async () => {
+    renderComponent({
+      statistics: {
+        data: {
+          ...statisticsFixture,
+          elementAnnotations: {},
+        },
+        loading: 'failed',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    expect(screen.getByText('Select annotations')).toBeInTheDocument();
+    const navigationButton = screen.getByTestId('accordion-item-button');
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument();
+  });
+
+  it('should display loading message when fetching data is pending', async () => {
+    renderComponent({
+      statistics: {
+        data: undefined,
+        loading: 'pending',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    expect(screen.getByText('Select annotations')).toBeInTheDocument();
+    const navigationButton = screen.getByTestId('accordion-item-button');
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.getByText('Loading...')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.tsx b/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.tsx
new file mode 100644
index 00000000..a68fd389
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.tsx
@@ -0,0 +1,40 @@
+/* eslint-disable no-magic-numbers */
+import {
+  Accordion,
+  AccordionItem,
+  AccordionItemButton,
+  AccordionItemHeading,
+  AccordionItemPanel,
+} from '@/shared/Accordion';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import {
+  elementAnnotationsSelector,
+  loadingStatisticsSelector,
+} from '@/redux/statistics/statistics.selectors';
+import { CheckboxFilter } from '../CheckboxFilter';
+
+export const Annotations = (): React.ReactNode => {
+  const loadingStatistics = useAppSelector(loadingStatisticsSelector);
+  const elementAnnotations = useAppSelector(elementAnnotationsSelector);
+  const isPending = loadingStatistics === 'pending';
+
+  const mappedElementAnnotations = elementAnnotations
+    ? Object.keys(elementAnnotations)?.map(el => ({ id: el, label: el }))
+    : [];
+
+  return (
+    <Accordion allowZeroExpanded>
+      <AccordionItem>
+        <AccordionItemHeading>
+          <AccordionItemButton>Select annotations</AccordionItemButton>
+        </AccordionItemHeading>
+        <AccordionItemPanel>
+          {isPending && <p>Loading...</p>}
+          {!isPending && mappedElementAnnotations && mappedElementAnnotations.length > 0 && (
+            <CheckboxFilter options={mappedElementAnnotations} />
+          )}
+        </AccordionItemPanel>
+      </AccordionItem>
+    </Accordion>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/Annotations/index.ts b/src/components/Map/Drawer/ExportDrawer/Annotations/index.ts
new file mode 100644
index 00000000..3b82aaf7
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Annotations/index.ts
@@ -0,0 +1 @@
+export { Annotations } from './Annotations.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.test.tsx
new file mode 100644
index 00000000..1fb3437a
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.test.tsx
@@ -0,0 +1,109 @@
+import React from 'react';
+import { render, screen, fireEvent } from '@testing-library/react';
+
+import { CheckboxFilter } from './CheckboxFilter.component';
+
+const options = [
+  { id: '1', label: 'Option 1' },
+  { id: '2', label: 'Option 2' },
+  { id: '3', label: 'Option 3' },
+];
+
+describe('CheckboxFilter - component', () => {
+  it('should render CheckboxFilter properly', () => {
+    render(<CheckboxFilter options={options} />);
+    expect(screen.getByTestId('search')).toBeInTheDocument();
+  });
+
+  it('should filter options based on search term', async () => {
+    render(<CheckboxFilter options={options} />);
+    const searchInput = screen.getByLabelText('search-input');
+
+    fireEvent.change(searchInput, { target: { value: `Option 1` } });
+
+    expect(screen.getByLabelText('Option 1')).toBeInTheDocument();
+    expect(screen.queryByText('Option 2')).not.toBeInTheDocument();
+    expect(screen.queryByText('Option 3')).not.toBeInTheDocument();
+  });
+
+  it('should handle checkbox value change', async () => {
+    const onCheckedChange = jest.fn();
+    render(<CheckboxFilter options={options} onCheckedChange={onCheckedChange} />);
+    const checkbox = screen.getByLabelText('Option 1');
+
+    fireEvent.click(checkbox);
+
+    expect(onCheckedChange).toHaveBeenCalledWith([{ id: '1', label: 'Option 1' }]);
+  });
+
+  it('should call onFilterChange when searching new term', async () => {
+    const onFilterChange = jest.fn();
+    render(<CheckboxFilter options={options} onFilterChange={onFilterChange} />);
+    const searchInput = screen.getByLabelText('search-input');
+
+    fireEvent.change(searchInput, { target: { value: 'Option 1' } });
+
+    expect(onFilterChange).toHaveBeenCalledWith([{ id: '1', label: 'Option 1' }]);
+  });
+  it('should display message when no elements are found', async () => {
+    render(<CheckboxFilter options={options} />);
+    const searchInput = screen.getByLabelText('search-input');
+
+    fireEvent.change(searchInput, { target: { value: 'Nonexistent Option' } });
+
+    expect(screen.getByText('No matching elements found.')).toBeInTheDocument();
+  });
+  it('should display message when options are empty', () => {
+    const onFilterChange = jest.fn();
+    render(<CheckboxFilter options={[]} onFilterChange={onFilterChange} />);
+
+    expect(screen.getByText('No matching elements found.')).toBeInTheDocument();
+  });
+  it('should handle multiple checkbox selection', () => {
+    const onCheckedChange = jest.fn();
+    render(<CheckboxFilter options={options} onCheckedChange={onCheckedChange} />);
+
+    const checkbox1 = screen.getByLabelText('Option 1');
+    const checkbox2 = screen.getByLabelText('Option 2');
+
+    fireEvent.click(checkbox1);
+    fireEvent.click(checkbox2);
+
+    expect(onCheckedChange).toHaveBeenCalledWith([
+      { id: '1', label: 'Option 1' },
+      { id: '2', label: 'Option 2' },
+    ]);
+  });
+  it('should handle unchecking a checkbox', () => {
+    const onCheckedChange = jest.fn();
+    render(<CheckboxFilter options={options} onCheckedChange={onCheckedChange} />);
+
+    const checkbox = screen.getByLabelText('Option 1');
+
+    fireEvent.click(checkbox); // Check
+    fireEvent.click(checkbox); // Uncheck
+
+    expect(onCheckedChange).toHaveBeenCalledWith([]);
+  });
+  it('should render search input when isSearchEnabled is true', () => {
+    render(<CheckboxFilter options={options} />);
+    const searchInput = screen.getByLabelText('search-input');
+    expect(searchInput).toBeInTheDocument();
+  });
+
+  it('should not render search input when isSearchEnabled is false', () => {
+    render(<CheckboxFilter options={options} isSearchEnabled={false} />);
+    const searchInput = screen.queryByLabelText('search-input');
+    expect(searchInput).not.toBeInTheDocument();
+  });
+
+  it('should not filter options based on search input when isSearchEnabled is false', () => {
+    render(<CheckboxFilter options={options} isSearchEnabled={false} />);
+    const searchInput = screen.queryByLabelText('search-input');
+    expect(searchInput).not.toBeInTheDocument();
+    options.forEach(option => {
+      const checkboxLabel = screen.getByText(option.label);
+      expect(checkboxLabel).toBeInTheDocument();
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx
new file mode 100644
index 00000000..68dbe9c6
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx
@@ -0,0 +1,105 @@
+/* eslint-disable no-magic-numbers */
+import Image from 'next/image';
+import React, { useEffect, useState } from 'react';
+import lensIcon from '@/assets/vectors/icons/lens.svg';
+import { twMerge } from 'tailwind-merge';
+
+type CheckboxItem = { id: string; label: string };
+
+type CheckboxFilterProps = {
+  options: CheckboxItem[];
+  onFilterChange?: (filteredItems: CheckboxItem[]) => void;
+  onCheckedChange?: (filteredItems: CheckboxItem[]) => void;
+  isSearchEnabled?: boolean;
+};
+
+export const CheckboxFilter = ({
+  options,
+  onFilterChange,
+  onCheckedChange,
+  isSearchEnabled = true,
+}: CheckboxFilterProps): React.ReactNode => {
+  const [searchTerm, setSearchTerm] = useState('');
+  const [filteredOptions, setFilteredOptions] = useState<CheckboxItem[]>(options);
+  const [checkedCheckboxes, setCheckedCheckboxes] = useState<CheckboxItem[]>([]);
+
+  const filterOptions = (term: string): void => {
+    const filteredItems = options.filter(item =>
+      item.label.toLowerCase().includes(term.toLowerCase()),
+    );
+
+    setFilteredOptions(filteredItems);
+    onFilterChange?.(filteredItems);
+  };
+
+  const handleSearchTermChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
+    const newSearchTerm = e.target.value;
+    setSearchTerm(newSearchTerm);
+    filterOptions(newSearchTerm);
+  };
+
+  const handleCheckboxChange = (option: CheckboxItem): void => {
+    const newCheckedCheckboxes = checkedCheckboxes.includes(option)
+      ? checkedCheckboxes.filter(item => item !== option)
+      : [...checkedCheckboxes, option];
+
+    setCheckedCheckboxes(newCheckedCheckboxes);
+    onCheckedChange?.(newCheckedCheckboxes);
+  };
+
+  useEffect(() => {
+    setFilteredOptions(options);
+  }, [options]);
+
+  return (
+    <div className="relative" data-testid="checkbox-filter">
+      {isSearchEnabled && (
+        <div className="relative" data-testid="search">
+          <input
+            name="search-input"
+            aria-label="search-input"
+            value={searchTerm}
+            onChange={handleSearchTermChange}
+            placeholder="Search..."
+            className="h-9 w-full rounded-[64px] border border-transparent bg-cultured px-4 py-2.5 text-xs font-medium text-font-400 outline-none  hover:border-greyscale-600 focus:border-greyscale-600"
+          />
+
+          <Image
+            src={lensIcon}
+            alt="lens icon"
+            height={16}
+            width={16}
+            className="absolute right-4 top-2.5"
+          />
+        </div>
+      )}
+
+      <div
+        className={twMerge(
+          'mb-6 max-h-[300px] overflow-y-auto py-2.5 pr-2.5',
+          isSearchEnabled && 'mt-6',
+        )}
+      >
+        {filteredOptions.length === 0 ? (
+          <p className="w-full text-sm text-font-400">No matching elements found.</p>
+        ) : (
+          <ul className="columns-2 gap-8">
+            {filteredOptions.map(option => (
+              <li key={option.id} className="mb-5 flex items-center gap-x-2">
+                <input
+                  type="checkbox"
+                  id={option.id}
+                  className=" h-4 w-4 shrink-0 accent-primary-500"
+                  onChange={(): void => handleCheckboxChange(option)}
+                />
+                <label htmlFor={option.id} className="break-all text-sm">
+                  {option.label}
+                </label>
+              </li>
+            ))}
+          </ul>
+        )}
+      </div>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/index.ts b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/index.ts
new file mode 100644
index 00000000..45a47c9f
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/index.ts
@@ -0,0 +1 @@
+export { CheckboxFilter } from './CheckboxFilter.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/CollapsibleSection/CollapsibleSection.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/CollapsibleSection/CollapsibleSection.component.test.tsx
new file mode 100644
index 00000000..99569fa0
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/CollapsibleSection/CollapsibleSection.component.test.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { render, screen, fireEvent } from '@testing-library/react';
+import { CollapsibleSection } from './CollapsibleSection.component';
+
+describe('CollapsibleSection - component', () => {
+  it('should render with title and content', () => {
+    render(
+      <CollapsibleSection title="Section">
+        <div>Content</div>
+      </CollapsibleSection>,
+    );
+
+    expect(screen.getByText('Section')).toBeInTheDocument();
+    expect(screen.getByText('Content')).toBeInTheDocument();
+  });
+
+  it('should collapse and expands on button click', () => {
+    render(
+      <CollapsibleSection title="Test Section">
+        <div>Test Content</div>
+      </CollapsibleSection>,
+    );
+
+    const button = screen.getByText('Test Section');
+    const content = screen.getByText('Test Content');
+
+    expect(content).not.toBeVisible();
+
+    // Expand
+    fireEvent.click(button);
+    expect(content).toBeVisible();
+
+    // Collapse
+    fireEvent.click(button);
+    expect(content).not.toBeVisible();
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/CollapsibleSection/CollapsibleSection.component.tsx b/src/components/Map/Drawer/ExportDrawer/CollapsibleSection/CollapsibleSection.component.tsx
new file mode 100644
index 00000000..b0d478bb
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/CollapsibleSection/CollapsibleSection.component.tsx
@@ -0,0 +1,26 @@
+import {
+  Accordion,
+  AccordionItem,
+  AccordionItemButton,
+  AccordionItemHeading,
+  AccordionItemPanel,
+} from '@/shared/Accordion';
+
+type CollapsibleSectionProps = {
+  title: string;
+  children: React.ReactNode;
+};
+
+export const CollapsibleSection = ({
+  title,
+  children,
+}: CollapsibleSectionProps): React.ReactNode => (
+  <Accordion allowZeroExpanded>
+    <AccordionItem>
+      <AccordionItemHeading>
+        <AccordionItemButton>{title}</AccordionItemButton>
+      </AccordionItemHeading>
+      <AccordionItemPanel>{children}</AccordionItemPanel>
+    </AccordionItem>
+  </Accordion>
+);
diff --git a/src/components/Map/Drawer/ExportDrawer/CollapsibleSection/index.ts b/src/components/Map/Drawer/ExportDrawer/CollapsibleSection/index.ts
new file mode 100644
index 00000000..7d4a61e4
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/CollapsibleSection/index.ts
@@ -0,0 +1 @@
+export { CollapsibleSection } from './CollapsibleSection.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.test.tsx
new file mode 100644
index 00000000..df19cb66
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.test.tsx
@@ -0,0 +1,122 @@
+import { render, screen, waitFor } from '@testing-library/react';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { StoreType } from '@/redux/store';
+import { statisticsFixture } from '@/models/fixtures/statisticsFixture';
+import { act } from 'react-dom/test-utils';
+import { Annotations } from './Annotations.component';
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <Annotations />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('Annotations - component', () => {
+  it('should display annotations checkboxes when fetching data is successful', async () => {
+    renderComponent({
+      statistics: {
+        data: {
+          ...statisticsFixture,
+          elementAnnotations: {
+            compartment: 1,
+            pathway: 0,
+          },
+        },
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible();
+
+    const navigationButton = screen.getByTestId('accordion-item-button');
+
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.getByText('Select annotations')).toBeInTheDocument();
+
+    await waitFor(() => {
+      expect(screen.getByTestId('checkbox-filter')).toBeInTheDocument();
+      expect(screen.getByLabelText('compartment')).toBeInTheDocument();
+      expect(screen.getByLabelText('search-input')).toBeInTheDocument();
+    });
+  });
+  it('should not display annotations checkboxes when fetching data fails', async () => {
+    renderComponent({
+      statistics: {
+        data: undefined,
+        loading: 'failed',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    expect(screen.getByText('Select annotations')).toBeInTheDocument();
+    const navigationButton = screen.getByTestId('accordion-item-button');
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument();
+  });
+  it('should not display annotations checkboxes when fetched data is empty object', async () => {
+    renderComponent({
+      statistics: {
+        data: {
+          ...statisticsFixture,
+          elementAnnotations: {},
+        },
+        loading: 'failed',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    expect(screen.getByText('Select annotations')).toBeInTheDocument();
+    const navigationButton = screen.getByTestId('accordion-item-button');
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument();
+  });
+
+  it('should display loading message when fetching data is pending', async () => {
+    renderComponent({
+      statistics: {
+        data: undefined,
+        loading: 'pending',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    expect(screen.getByText('Select annotations')).toBeInTheDocument();
+    const navigationButton = screen.getByTestId('accordion-item-button');
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.getByText('Loading...')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.tsx
new file mode 100644
index 00000000..f3795e9b
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.tsx
@@ -0,0 +1,27 @@
+/* eslint-disable no-magic-numbers */
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import {
+  elementAnnotationsSelector,
+  loadingStatisticsSelector,
+} from '@/redux/statistics/statistics.selectors';
+import { CheckboxFilter } from '../../CheckboxFilter';
+import { CollapsibleSection } from '../../CollapsibleSection';
+
+export const Annotations = (): React.ReactNode => {
+  const loadingStatistics = useAppSelector(loadingStatisticsSelector);
+  const elementAnnotations = useAppSelector(elementAnnotationsSelector);
+  const isPending = loadingStatistics === 'pending';
+
+  const mappedElementAnnotations = elementAnnotations
+    ? Object.keys(elementAnnotations)?.map(el => ({ id: el, label: el }))
+    : [];
+
+  return (
+    <CollapsibleSection title="Select annotations">
+      {isPending && <p>Loading...</p>}
+      {!isPending && mappedElementAnnotations && mappedElementAnnotations.length > 0 && (
+        <CheckboxFilter options={mappedElementAnnotations} />
+      )}
+    </CollapsibleSection>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/index.ts b/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/index.ts
new file mode 100644
index 00000000..3b82aaf7
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/index.ts
@@ -0,0 +1 @@
+export { Annotations } from './Annotations.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.test.tsx
new file mode 100644
index 00000000..381ba5cc
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.test.tsx
@@ -0,0 +1,26 @@
+import { render, screen } from '@testing-library/react';
+import { act } from 'react-dom/test-utils';
+import { Columns } from './Columns.component';
+
+describe('Columns - component', () => {
+  it('should display select column accordion', async () => {
+    render(<Columns />);
+
+    expect(screen.getByText('Select column')).toBeInTheDocument();
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible();
+  });
+  it('should display columns checkboxes', async () => {
+    render(<Columns />);
+
+    expect(screen.getByText('Select column')).toBeInTheDocument();
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible();
+
+    const navigationButton = screen.getByTestId('accordion-item-button');
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).toBeVisible();
+    expect(screen.queryByLabelText('References')).toBeVisible();
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.tsx
new file mode 100644
index 00000000..c6d8084f
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.tsx
@@ -0,0 +1,9 @@
+import { CheckboxFilter } from '../../CheckboxFilter';
+import { CollapsibleSection } from '../../CollapsibleSection';
+import { COLUMNS } from './Columns.constants';
+
+export const Columns = (): React.ReactNode => (
+  <CollapsibleSection title="Select column">
+    <CheckboxFilter options={COLUMNS} isSearchEnabled={false} />
+  </CollapsibleSection>
+);
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.constants.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.constants.tsx
new file mode 100644
index 00000000..e2ece6b5
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.constants.tsx
@@ -0,0 +1,86 @@
+export const COLUMNS = [
+  {
+    id: 'id',
+    label: 'ID',
+  },
+  {
+    id: 'description',
+    label: 'Description',
+  },
+  {
+    id: 'modelId',
+    label: 'Map id',
+  },
+  {
+    id: 'mapName',
+    label: 'Map name',
+  },
+  {
+    id: 'symbol',
+    label: 'Symbol',
+  },
+  {
+    id: 'abbreviation',
+    label: 'Abbreviation',
+  },
+  {
+    id: 'synonyms',
+    label: 'Synonyms',
+  },
+  {
+    id: 'references',
+    label: 'References',
+  },
+  {
+    id: 'name',
+    label: 'Name',
+  },
+  {
+    id: 'type',
+    label: 'Type',
+  },
+  {
+    id: 'complexId',
+    label: 'Complex id',
+  },
+  {
+    id: 'complexName',
+    label: 'Complex name',
+  },
+  {
+    id: 'compartmentId',
+    label: 'Compartment/Pathway id',
+  },
+  {
+    id: 'compartmentName',
+    label: 'Compartment/Pathway name',
+  },
+  {
+    id: 'charge',
+    label: 'Charge',
+  },
+  {
+    id: 'fullName',
+    label: 'Full name',
+  },
+  {
+    id: 'formula',
+    label: 'Formula',
+  },
+  {
+    id: 'formerSymbols',
+    label: 'Former symbols',
+  },
+  {
+    id: 'linkedSubmodelId',
+    label: 'Linked submap id',
+  },
+  {
+    id: 'elementId',
+    label: 'Element external id',
+  },
+  {
+    id: 'ALL',
+    label: 'All',
+  },
+];
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Columns/index.ts b/src/components/Map/Drawer/ExportDrawer/Elements/Columns/index.ts
new file mode 100644
index 00000000..167db867
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Columns/index.ts
@@ -0,0 +1 @@
+export { Columns } from './Columns.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx
new file mode 100644
index 00000000..c4d5d6f4
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx
@@ -0,0 +1,13 @@
+import { Types } from './Types';
+import { Annotations } from '../Annotations';
+import { Columns } from './Columns';
+
+export const Elements = (): React.ReactNode => {
+  return (
+    <div data-testid="elements-tab">
+      <Types />
+      <Columns />
+      <Annotations />
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.test.tsx
new file mode 100644
index 00000000..4d228509
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.test.tsx
@@ -0,0 +1,29 @@
+import { render, screen } from '@testing-library/react';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { StoreType } from '@/redux/store';
+import { Types } from './Types.component';
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <Types />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('Types Component', () => {
+  test('renders without crashing', () => {
+    renderComponent();
+    expect(screen.getByText('Select types')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.tsx
new file mode 100644
index 00000000..0c37bdf6
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.tsx
@@ -0,0 +1,16 @@
+import { elementTypesSelector } from '@/redux/configuration/configuration.selectors';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { getCheckboxElements } from './Types.utils';
+import { CheckboxFilter } from '../../CheckboxFilter';
+import { CollapsibleSection } from '../../CollapsibleSection';
+
+export const Types = (): React.ReactNode => {
+  const elementTypes = useAppSelector(elementTypesSelector);
+  const checkboxElements = getCheckboxElements(elementTypes);
+
+  return (
+    <CollapsibleSection title="Select types">
+      {checkboxElements && <CheckboxFilter options={checkboxElements} isSearchEnabled={false} />}
+    </CollapsibleSection>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.test.ts b/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.test.ts
new file mode 100644
index 00000000..34e10ae6
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.test.ts
@@ -0,0 +1,36 @@
+import { getCheckboxElements } from './Types.utils';
+
+describe('getCheckboxElements', () => {
+  it('should return an empty array when elementTypes is undefined', () => {
+    const result = getCheckboxElements(undefined);
+    expect(result).toEqual([]);
+  });
+
+  it('should map elementTypes to MappedElementTypes and exclude duplicates based on name and parentClass', () => {
+    const elementTypes = [
+      { className: 'class1', name: 'type1', parentClass: 'parent1' },
+      { className: 'class2', name: 'type2', parentClass: 'parent2' },
+      { className: 'class1', name: 'type1', parentClass: 'parent1' },
+      { className: 'class3', name: 'type3', parentClass: 'parent3' },
+      { className: 'class2', name: 'type2', parentClass: 'parent2' },
+    ];
+
+    const result = getCheckboxElements(elementTypes);
+
+    expect(result).toEqual([
+      { id: 'type1', label: 'type1' },
+      { id: 'type2', label: 'type2' },
+      { id: 'type3', label: 'type3' },
+    ]);
+  });
+
+  it('should handle an empty array of elementTypes', () => {
+    const result = getCheckboxElements([]);
+    expect(result).toEqual([]);
+  });
+
+  it('should return an empty array when elementTypes is undefined', () => {
+    const result = getCheckboxElements(undefined);
+    expect(result).toEqual([]);
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.ts b/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.ts
new file mode 100644
index 00000000..a8a7cc99
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.ts
@@ -0,0 +1,35 @@
+type ElementTypes =
+  | {
+      className: string;
+      name: string;
+      parentClass: string;
+    }[]
+  | undefined;
+
+type MappedElementTypes = { id: string; label: string }[];
+
+type PresenceMap = { [key: string]: boolean };
+
+export const getCheckboxElements = (elementTypes: ElementTypes): MappedElementTypes => {
+  if (!elementTypes) return [];
+
+  const excludedTypes: PresenceMap = {};
+  elementTypes?.forEach(type => {
+    excludedTypes[type.parentClass] = true;
+  });
+
+  const mappedElementTypes: MappedElementTypes = [];
+  const processedNames: PresenceMap = {};
+
+  elementTypes.forEach(elementType => {
+    if (excludedTypes[elementType.className] || processedNames[elementType.name]) return;
+
+    processedNames[elementType.name] = true;
+    mappedElementTypes.push({
+      id: elementType.name,
+      label: elementType.name,
+    });
+  });
+
+  return mappedElementTypes;
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Types/index.ts b/src/components/Map/Drawer/ExportDrawer/Elements/Types/index.ts
new file mode 100644
index 00000000..ce8a0cc1
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Types/index.ts
@@ -0,0 +1 @@
+export { Types } from './Types.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/index.ts b/src/components/Map/Drawer/ExportDrawer/Elements/index.ts
new file mode 100644
index 00000000..4a0d339a
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/index.ts
@@ -0,0 +1 @@
+export { Elements } from './Elements.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.test.tsx
new file mode 100644
index 00000000..cec6029b
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.test.tsx
@@ -0,0 +1,70 @@
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { StoreType } from '@/redux/store';
+import { render, screen } from '@testing-library/react';
+import { openedExportDrawerFixture } from '@/redux/drawer/drawerFixture';
+import { act } from 'react-dom/test-utils';
+import { ExportDrawer } from './ExportDrawer.component';
+import { TAB_NAMES } from './TabNavigator/TabNavigator.constants';
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <ExportDrawer />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('ExportDrawer - component', () => {
+  it('should display drawer heading and tab names', () => {
+    renderComponent();
+
+    expect(screen.getByText('Export')).toBeInTheDocument();
+
+    Object.keys(TAB_NAMES).forEach(label => {
+      expect(screen.getByText(label)).toBeInTheDocument();
+    });
+  });
+  it('should close drawer after clicking close button', () => {
+    const { store } = renderComponent({
+      drawer: openedExportDrawerFixture,
+    });
+    const closeButton = screen.getByRole('close-drawer-button');
+
+    closeButton.click();
+
+    const {
+      drawer: { isOpen },
+    } = store.getState();
+
+    expect(isOpen).toBe(false);
+  });
+  it('should set elements as initial tab', () => {
+    renderComponent();
+
+    expect(screen.getByTestId('elements-tab')).toBeInTheDocument();
+  });
+  it('should set correct tab on tab change', () => {
+    renderComponent();
+    const currentTab = screen.getByRole('button', { current: true });
+    const networkTab = screen.getByText(/network/i);
+    const elementsTab = screen.getByTestId('elements-tab');
+    expect(currentTab).not.toBe(networkTab);
+    expect(screen.getByTestId('elements-tab')).toBeInTheDocument();
+
+    act(() => {
+      networkTab.click();
+    });
+    expect(screen.getByRole('button', { current: true })).toBe(networkTab);
+    expect(elementsTab).not.toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx
new file mode 100644
index 00000000..068348d1
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx
@@ -0,0 +1,24 @@
+import { DrawerHeading } from '@/shared/DrawerHeading';
+import { useState } from 'react';
+import { TabNavigator } from './TabNavigator';
+import { Elements } from './Elements';
+import { TAB_NAMES } from './TabNavigator/TabNavigator.constants';
+import { TabNames } from './TabNavigator/TabNavigator.types';
+
+export const ExportDrawer = (): React.ReactNode => {
+  const [activeTab, setActiveTab] = useState<TabNames>(TAB_NAMES.ELEMENTS);
+
+  const handleTabChange = (tabName: TabNames): void => {
+    setActiveTab(tabName);
+  };
+
+  return (
+    <div data-testid="export-drawer" className="h-full max-h-full">
+      <DrawerHeading title="Export" />
+      <div className="h-[calc(100%-93px)] max-h-[calc(100%-93px)] overflow-y-auto px-6">
+        <TabNavigator activeTab={activeTab} onTabChange={handleTabChange} />
+        {activeTab === TAB_NAMES.ELEMENTS && <Elements />}
+      </div>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/TabButton/TabButton.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/TabButton/TabButton.component.test.tsx
new file mode 100644
index 00000000..e4c872bd
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/TabButton/TabButton.component.test.tsx
@@ -0,0 +1,37 @@
+import { RenderResult, fireEvent, render, screen } from '@testing-library/react';
+import { TabButton } from './TabButton.component';
+
+const mockHandleChangeTab = jest.fn();
+
+const renderTabButton = (label: string, active = false): RenderResult =>
+  render(<TabButton label={label} handleChangeTab={mockHandleChangeTab} active={active} />);
+
+describe('TabButton - component', () => {
+  it('should render TabButton with custom label', () => {
+    renderTabButton('Map');
+
+    expect(screen.getByText('Map')).toBeInTheDocument();
+  });
+
+  it('should handle click event', () => {
+    renderTabButton('Network');
+
+    fireEvent.click(screen.getByText('Network'));
+    expect(mockHandleChangeTab).toHaveBeenCalled();
+  });
+
+  it('should indicate active tab correctly', () => {
+    renderTabButton('Graphics', true);
+
+    const currentTab = screen.getByRole('button', { current: true });
+    expect(currentTab).toHaveTextContent('Graphics');
+  });
+  it('should indicate not active tab correctly', () => {
+    renderTabButton('Graphics');
+
+    const activeTab = screen.queryByRole('button', { current: true });
+    const graphicsTab = screen.getByRole('button', { current: false });
+    expect(activeTab).not.toBeInTheDocument();
+    expect(graphicsTab).toHaveTextContent('Graphics');
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/TabButton/TabButton.component.tsx b/src/components/Map/Drawer/ExportDrawer/TabButton/TabButton.component.tsx
new file mode 100644
index 00000000..c30a1082
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/TabButton/TabButton.component.tsx
@@ -0,0 +1,22 @@
+import { twMerge } from 'tailwind-merge';
+
+type TabButtonProps = {
+  handleChangeTab: () => void;
+  active: boolean;
+  label: string;
+};
+
+export const TabButton = ({ handleChangeTab, active, label }: TabButtonProps): React.ReactNode => (
+  <button
+    type="button"
+    className={twMerge(
+      'text-sm font-normal text-[#979797]',
+      active &&
+        'relative py-2.5 font-semibold leading-6 text-cetacean-blue before:absolute before:inset-x-0 before:top-0 before:block before:h-1 before:rounded-b before:bg-primary-500 before:content-[""]',
+    )}
+    aria-current={active}
+    onClick={handleChangeTab}
+  >
+    {label}
+  </button>
+);
diff --git a/src/components/Map/Drawer/ExportDrawer/TabButton/index.ts b/src/components/Map/Drawer/ExportDrawer/TabButton/index.ts
new file mode 100644
index 00000000..f22cacf6
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/TabButton/index.ts
@@ -0,0 +1 @@
+export { TabButton } from './TabButton.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.component.test.tsx
new file mode 100644
index 00000000..c604f80e
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.component.test.tsx
@@ -0,0 +1,36 @@
+import { fireEvent, render, screen } from '@testing-library/react';
+import { TAB_NAMES } from './TabNavigator.constants';
+import { TabNavigator } from './TabNavigator.component';
+
+const mockOnTabChange = jest.fn();
+
+describe('TabNavigator - component', () => {
+  beforeEach(() => {
+    mockOnTabChange.mockReset();
+  });
+  it('should render TabNavigator with correct tabs', () => {
+    render(<TabNavigator activeTab="elements" onTabChange={mockOnTabChange} />);
+
+    Object.keys(TAB_NAMES).forEach(label => {
+      expect(screen.getByText(label)).toBeInTheDocument();
+    });
+  });
+
+  it('should change tabs correctly', () => {
+    render(<TabNavigator activeTab="elements" onTabChange={mockOnTabChange} />);
+
+    fireEvent.click(screen.getByText(/network/i));
+    expect(mockOnTabChange).toHaveBeenCalledWith('network');
+
+    fireEvent.click(screen.getByText(/graphics/i));
+    expect(mockOnTabChange).toHaveBeenCalledWith('graphics');
+  });
+
+  it('should set initial active tab', () => {
+    render(<TabNavigator activeTab="network" onTabChange={mockOnTabChange} />);
+    const currentTab = screen.getByRole('button', { current: true });
+    const networkTab = screen.getByText(/network/i);
+
+    expect(currentTab).toBe(networkTab);
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.component.tsx b/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.component.tsx
new file mode 100644
index 00000000..e8714166
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.component.tsx
@@ -0,0 +1,21 @@
+import { TabButton } from '../TabButton';
+import { TAB_NAMES } from './TabNavigator.constants';
+import { TabNames } from './TabNavigator.types';
+
+type TabNavigatorProps = {
+  activeTab: TabNames;
+  onTabChange: (tabName: TabNames) => void;
+};
+
+export const TabNavigator = ({ activeTab, onTabChange }: TabNavigatorProps): React.ReactNode => (
+  <div className="flex gap-5">
+    {Object.entries(TAB_NAMES).map(([label, tabName]) => (
+      <TabButton
+        key={tabName}
+        handleChangeTab={(): void => onTabChange(tabName)}
+        label={label}
+        active={activeTab === tabName}
+      />
+    ))}
+  </div>
+);
diff --git a/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.constants.ts b/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.constants.ts
new file mode 100644
index 00000000..3eda3a54
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.constants.ts
@@ -0,0 +1,5 @@
+export const TAB_NAMES = {
+  ELEMENTS: 'elements',
+  NETWORK: 'network',
+  GRAPHICS: 'graphics',
+} as const;
diff --git a/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.types.ts b/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.types.ts
new file mode 100644
index 00000000..cd0ee383
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/TabNavigator/TabNavigator.types.ts
@@ -0,0 +1,3 @@
+import { TAB_NAMES } from './TabNavigator.constants';
+
+export type TabNames = (typeof TAB_NAMES)[keyof typeof TAB_NAMES];
diff --git a/src/components/Map/Drawer/ExportDrawer/TabNavigator/index.ts b/src/components/Map/Drawer/ExportDrawer/TabNavigator/index.ts
new file mode 100644
index 00000000..b471dcc5
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/TabNavigator/index.ts
@@ -0,0 +1 @@
+export { TabNavigator } from './TabNavigator.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/index.ts b/src/components/Map/Drawer/ExportDrawer/index.ts
new file mode 100644
index 00000000..313d407d
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/index.ts
@@ -0,0 +1 @@
+export { ExportDrawer } from './ExportDrawer.component';
diff --git a/src/components/Map/Drawer/OverlaysDrawer/OverlaysDrawer.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/OverlaysDrawer.component.tsx
index c64ecf74..15b84a16 100644
--- a/src/components/Map/Drawer/OverlaysDrawer/OverlaysDrawer.component.tsx
+++ b/src/components/Map/Drawer/OverlaysDrawer/OverlaysDrawer.component.tsx
@@ -1,15 +1,26 @@
 import { DrawerHeading } from '@/shared/DrawerHeading';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { currentStepOverlayDrawerStateSelector } from '@/redux/drawer/drawer.selectors';
+import { STEP } from '@/constants/searchDrawer';
 import { GeneralOverlays } from './GeneralOverlays';
 import { UserOverlays } from './UserOverlays';
+import { UserOverlayForm } from './UserOverlayForm';
 
 export const OverlaysDrawer = (): JSX.Element => {
+  const currentStep = useAppSelector(currentStepOverlayDrawerStateSelector);
+
   return (
     <div data-testid="overlays-drawer" className="h-full max-h-full">
-      <DrawerHeading title="Overlays" />
-      <div className="h-[calc(100%-93px)] max-h-[calc(100%-93px)] overflow-y-auto">
-        <GeneralOverlays />
-        <UserOverlays />
-      </div>
+      {currentStep === STEP.FIRST && (
+        <>
+          <DrawerHeading title="Overlays" />
+          <div className="h-[calc(100%-93px)] max-h-[calc(100%-93px)] overflow-y-auto">
+            <GeneralOverlays />
+            <UserOverlays />
+          </div>
+        </>
+      )}
+      {currentStep === STEP.SECOND && <UserOverlayForm />}
     </div>
   );
 };
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/FileUpload.component.test.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/FileUpload.component.test.tsx
new file mode 100644
index 00000000..83a68bfa
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/FileUpload.component.test.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { FileUpload } from './FileUpload.component';
+
+describe('FileUpload component', () => {
+  const handleChangeFile = jest.fn();
+  const handleChangeOverlayContent = jest.fn();
+  const handleOverlayChange = jest.fn();
+  const uploadedFile = new File(['file content'], 'test.txt', {
+    type: 'text/plain',
+  });
+
+  afterEach(() => {
+    jest.clearAllMocks();
+  });
+
+  it('renders correctly with default state', () => {
+    render(
+      <FileUpload
+        handleChangeFile={handleChangeFile}
+        handleChangeOverlayContent={handleChangeOverlayContent}
+        updateUserOverlayForm={handleOverlayChange}
+        uploadedFile={null}
+      />,
+    );
+
+    expect(screen.getByText(/drag and drop here or/i)).toBeInTheDocument();
+  });
+
+  it('renders filename when file type is correct', () => {
+    render(
+      <FileUpload
+        handleChangeFile={handleChangeFile}
+        handleChangeOverlayContent={handleChangeOverlayContent}
+        updateUserOverlayForm={handleOverlayChange}
+        uploadedFile={uploadedFile}
+      />,
+    );
+
+    expect(screen.getByText(/test.txt/i)).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/FileUpload.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/FileUpload.component.tsx
new file mode 100644
index 00000000..4370a451
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/FileUpload.component.tsx
@@ -0,0 +1,62 @@
+/* eslint-disable no-magic-numbers */
+import React from 'react';
+import { useDropzone } from 'react-dropzone';
+import { processOverlayContentChange } from '../UserOverlayForm.utils';
+
+type FileUploadProps = {
+  updateUserOverlayForm: (nameType: string, value: string) => void;
+  handleChangeOverlayContent: (value: string) => void;
+  handleChangeFile: (value: File) => void;
+  uploadedFile: File | null;
+};
+
+export const FileUpload = ({
+  handleChangeFile,
+  handleChangeOverlayContent,
+  updateUserOverlayForm,
+  uploadedFile,
+}: FileUploadProps): React.ReactNode => {
+  const { getRootProps, getInputProps, isDragActive, isDragReject } = useDropzone({
+    accept: {
+      'text/plain': ['.txt'],
+    },
+    onDrop: acceptedFiles => {
+      handleChangeFile(acceptedFiles[0]);
+
+      const file = acceptedFiles[0];
+      if (file) {
+        const reader = new FileReader();
+        reader.readAsText(file);
+        reader.onload = (e): void => {
+          if (e.target) {
+            const content = e.target?.result as string;
+            handleChangeOverlayContent(content);
+            processOverlayContentChange(content, updateUserOverlayForm);
+          }
+        };
+      }
+    },
+  });
+
+  return (
+    <div
+      {...getRootProps()}
+      className="flex h-16 items-center justify-center rounded-lg bg-cultured"
+      data-testid="dropzone"
+    >
+      <input {...getInputProps()} data-testid="dropzone-input" />
+      <p className="text-xs font-semibold">
+        {uploadedFile && uploadedFile.name}
+
+        {isDragActive && !isDragReject && 'Drop the file here ...'}
+
+        {!isDragActive && !uploadedFile && (
+          <>
+            Drag and drop here or <span className="text-[#004DE2]">browse</span>
+          </>
+        )}
+        {isDragReject && 'Invalid file type. Please choose a supported format .txt'}
+      </p>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/index.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/index.ts
new file mode 100644
index 00000000..07a87a8d
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/FileUpload/index.ts
@@ -0,0 +1 @@
+export { FileUpload } from './FileUpload.component';
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/OverlaySelector.component.test.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/OverlaySelector.component.test.tsx
new file mode 100644
index 00000000..acc140eb
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/OverlaySelector.component.test.tsx
@@ -0,0 +1,48 @@
+/* eslint-disable no-magic-numbers */
+import React from 'react';
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import { OverlaySelector } from './OverlaySelector.component';
+import { SelectorItem } from '../UserOverlayForm.types';
+
+const items: SelectorItem[] = [
+  { id: '1', label: 'Item 1' },
+  { id: '2', label: 'Item 2' },
+  { id: '3', label: 'Item 3' },
+];
+
+const onChangeMock = jest.fn();
+
+describe('OverlaySelector component', () => {
+  it('renders the component with initial values', () => {
+    const label = 'Select an item';
+    const value = items[0];
+
+    render(<OverlaySelector items={items} value={value} onChange={onChangeMock} label={label} />);
+
+    expect(screen.getByText(label)).toBeInTheDocument();
+
+    expect(screen.getByTestId('selector-dropdown-button-name')).toHaveTextContent(value.label);
+  });
+
+  it('opens the dropdown and selects an item', () => {
+    const label = 'Select an item';
+    const value = items[0];
+
+    render(<OverlaySelector items={items} value={value} onChange={onChangeMock} label={label} />);
+
+    fireEvent.click(screen.getByTestId('selector-dropdown-button-name'));
+
+    expect(screen.getByRole('listbox')).toBeInTheDocument();
+
+    const selectedItem = items[1];
+    const firstItem = screen.getByText(selectedItem.label);
+
+    fireEvent.click(firstItem);
+
+    waitFor(() => {
+      expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
+    });
+
+    expect(onChangeMock).toHaveBeenCalledWith(selectedItem);
+  });
+});
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/OverlaySelector.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/OverlaySelector.component.tsx
new file mode 100644
index 00000000..0e29ed5f
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/OverlaySelector.component.tsx
@@ -0,0 +1,84 @@
+/* eslint-disable no-magic-numbers */
+import { useSelect } from 'downshift';
+
+import { twMerge } from 'tailwind-merge';
+import { Icon } from '@/shared/Icon';
+import { SelectorItem } from '../UserOverlayForm.types';
+
+type OverlaySelectorProps = {
+  items: SelectorItem[];
+  value: SelectorItem;
+  onChange: (item: SelectorItem) => void;
+  label: string;
+};
+
+export const OverlaySelector = ({
+  items,
+  value,
+  onChange,
+  label,
+}: OverlaySelectorProps): JSX.Element => {
+  const onItemSelect = (item: SelectorItem | undefined | null): void => {
+    if (item) {
+      onChange(item);
+    }
+  };
+
+  const {
+    isOpen,
+    getToggleButtonProps,
+    getMenuProps,
+    highlightedIndex,
+    getItemProps,
+    selectedItem,
+  } = useSelect({
+    items,
+    defaultSelectedItem: items[0],
+    selectedItem: value,
+    onSelectedItemChange: ({ selectedItem: newSelectedItem }) => onItemSelect(newSelectedItem),
+  });
+
+  return (
+    <div className="mb-2.5">
+      <p className="my-2.5 text-sm">{label}</p>
+
+      <div className={twMerge('relative rounded-t bg-cultured text-xs', !isOpen && 'rounded-b')}>
+        <div className={twMerge('flex w-full flex-col rounded-t py-2 pl-4 pr-3')}>
+          <div
+            {...getToggleButtonProps()}
+            className="flex cursor-pointer flex-row items-center justify-between bg-cultured"
+          >
+            <span data-testid="selector-dropdown-button-name" className="font-medium">
+              {selectedItem?.label}
+            </span>
+            <Icon
+              name="chevron-down"
+              className={twMerge('arrow-button h-6 w-6 fill-primary-500', isOpen && 'rotate-180')}
+            />
+          </div>
+        </div>
+        <ul
+          {...getMenuProps()}
+          className={`absolute inset-x-0 z-10 max-h-80 w-full overflow-scroll rounded-b bg-cultured p-0 ${
+            !isOpen && 'hidden'
+          }`}
+        >
+          {isOpen &&
+            items.map((item, index) => (
+              <li
+                className={twMerge(
+                  'border-t',
+                  highlightedIndex === index && 'text-primary-500',
+                  'flex flex-col px-4 py-2',
+                )}
+                key={item.id}
+                {...getItemProps({ item, index })}
+              >
+                <span>{item.label}</span>
+              </li>
+            ))}
+        </ul>
+      </div>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/index.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/index.ts
new file mode 100644
index 00000000..147e4894
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/OverlaySelector/index.ts
@@ -0,0 +1 @@
+export { OverlaySelector } from './OverlaySelector.component';
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx
new file mode 100644
index 00000000..b7c754c8
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx
@@ -0,0 +1,240 @@
+/* eslint-disable no-magic-numbers */
+import React from 'react';
+import { render, screen, fireEvent } from '@testing-library/react';
+import { projectFixture } from '@/models/fixtures/projectFixture';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { AppDispatch, RootState, StoreType } from '@/redux/store';
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { drawerOverlaysStepOneFixture } from '@/redux/drawer/drawerFixture';
+import { MockStoreEnhanced } from 'redux-mock-store';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { HttpStatusCode } from 'axios';
+import { apiPath } from '@/redux/apiPath';
+import {
+  createdOverlayFileFixture,
+  createdOverlayFixture,
+  uploadedOverlayFileContentFixture,
+} from '@/models/fixtures/overlaysFixture';
+import { UserOverlayForm } from './UserOverlayForm.component';
+
+const mockedAxiosClient = mockNetworkResponse();
+
+const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
+  return (
+    render(
+      <Wrapper>
+        <UserOverlayForm />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+const renderComponentWithActionListener = (
+  initialStoreState: InitialStoreState = {},
+): { store: MockStoreEnhanced<Partial<RootState>, AppDispatch> } => {
+  const { Wrapper, store } = getReduxStoreWithActionsListener(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <UserOverlayForm />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('UserOverlayForm - Component', () => {
+  it('renders the UserOverlayForm component', () => {
+    renderComponent();
+
+    expect(screen.getByTestId('overlay-name')).toBeInTheDocument();
+    expect(screen.getByLabelText('upload overlay')).toBeInTheDocument();
+  });
+
+  it('should submit the form with elements list when upload button is clicked', async () => {
+    mockedAxiosClient
+      .onPost(apiPath.createOverlayFile())
+      .reply(HttpStatusCode.Ok, createdOverlayFileFixture);
+
+    mockedAxiosClient
+      .onPost(apiPath.uploadOverlayFileContent(123))
+      .reply(HttpStatusCode.Ok, uploadedOverlayFileContentFixture);
+
+    mockedAxiosClient
+      .onPost(apiPath.createOverlay('pd'))
+      .reply(HttpStatusCode.Ok, createdOverlayFixture);
+
+    renderComponent({
+      project: {
+        data: projectFixture,
+        loading: 'succeeded',
+        error: { message: '', name: '' },
+      },
+      overlays: {
+        data: [],
+        loading: 'idle',
+        error: DEFAULT_ERROR,
+        addOverlay: {
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    fireEvent.change(screen.getByTestId('overlay-name'), { target: { value: 'Test Overlay' } });
+    fireEvent.change(screen.getByTestId('overlay-description'), {
+      target: { value: 'Description Overlay' },
+    });
+    fireEvent.change(screen.getByTestId('overlay-elements-list'), {
+      target: { value: 'Elements List Overlay' },
+    });
+
+    fireEvent.click(screen.getByLabelText('upload overlay'));
+
+    expect(screen.getByLabelText('upload overlay')).toBeDisabled();
+  });
+
+  it('should create correct name for file which contains elements list as content', async () => {
+    const { store } = renderComponentWithActionListener({
+      project: {
+        data: projectFixture,
+        loading: 'succeeded',
+        error: { message: '', name: '' },
+      },
+      overlays: {
+        data: [],
+        loading: 'idle',
+        error: DEFAULT_ERROR,
+        addOverlay: {
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    fireEvent.change(screen.getByTestId('overlay-name'), { target: { value: 'Test Overlay' } });
+    fireEvent.change(screen.getByTestId('overlay-description'), {
+      target: { value: 'Description Overlay' },
+    });
+    fireEvent.change(screen.getByTestId('overlay-elements-list'), {
+      target: { value: 'Elements List Overlay' },
+    });
+
+    const actions = store.getActions();
+    fireEvent.click(screen.getByLabelText('upload overlay'));
+
+    expect(actions[0].meta.arg.filename).toBe('unknown.txt');
+  });
+
+  it('should update the form inputs based on overlay content provided by elements list', async () => {
+    renderComponent({
+      overlays: {
+        data: [],
+        loading: 'idle',
+        error: DEFAULT_ERROR,
+        addOverlay: {
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    fireEvent.change(screen.getByTestId('overlay-name'), { target: { value: 'Test Overlay' } });
+    fireEvent.change(screen.getByTestId('overlay-description'), {
+      target: { value: 'Description Overlay' },
+    });
+
+    fireEvent.change(screen.getByTestId('overlay-elements-list'), {
+      target: {
+        value: '#NAME = John\n# DESCRIPTION = Some description\n# TYPE = GENETIC_VARIANT\n',
+      },
+    });
+
+    expect(screen.getByTestId('overlay-name')).toHaveValue('John');
+    expect(screen.getByTestId('overlay-description')).toHaveValue('Some description');
+    expect(screen.getByText('GENETIC_VARIANT')).toBeVisible();
+  });
+
+  it('should display correct filename', async () => {
+    const uploadedFile = new File(['file content'], 'test.txt', {
+      type: 'text/plain',
+    });
+    renderComponent({
+      overlays: {
+        data: [],
+        loading: 'idle',
+        error: DEFAULT_ERROR,
+        addOverlay: {
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    fireEvent.change(screen.getByTestId('dropzone-input'), {
+      target: { files: [uploadedFile] },
+    });
+
+    const dropzone: HTMLInputElement = screen.getByTestId('dropzone-input');
+    expect(dropzone?.files?.[0].name).toBe('test.txt');
+  });
+
+  it('should not submit when form is not filled', async () => {
+    renderComponent({
+      overlays: {
+        data: [],
+        loading: 'idle',
+        error: DEFAULT_ERROR,
+        addOverlay: {
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+    expect(screen.getByTestId('overlay-description')).toHaveValue('');
+    fireEvent.click(screen.getByLabelText('upload overlay'));
+    expect(screen.getByLabelText('upload overlay')).not.toBeDisabled();
+  });
+  it('should navigate to overlays after clicking backward button', async () => {
+    const { store } = renderComponent({
+      drawer: drawerOverlaysStepOneFixture,
+      project: {
+        data: projectFixture,
+        loading: 'succeeded',
+        error: { message: '', name: '' },
+      },
+      overlays: {
+        data: [],
+        loading: 'idle',
+        error: DEFAULT_ERROR,
+        addOverlay: {
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    const backButton = screen.getByRole('back-button');
+
+    backButton.click();
+
+    const {
+      drawer: {
+        overlayDrawerState: { currentStep },
+      },
+    } = store.getState();
+
+    expect(currentStep).toBe(1);
+  });
+});
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.tsx
new file mode 100644
index 00000000..ed8f04b7
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.tsx
@@ -0,0 +1,121 @@
+/* eslint-disable no-magic-numbers */
+import { DrawerHeadingBackwardButton } from '@/shared/DrawerHeadingBackwardButton';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { openOverlaysDrawer } from '@/redux/drawer/drawer.slice';
+import { Button } from '@/shared/Button';
+import { Input } from '@/shared/Input';
+import { Textarea } from '@/shared/Textarea';
+import { OverlaySelector } from './OverlaySelector';
+import { OVERLAY_GROUPS, OVERLAY_TYPES } from './UserOverlayForm.constants';
+import { FileUpload } from './FileUpload';
+import { useUserOverlayForm } from './hooks/useUserOverlayForm';
+
+export const UserOverlayForm = (): React.ReactNode => {
+  const dispatch = useAppDispatch();
+  const {
+    name,
+    type,
+    group,
+    description,
+    uploadedFile,
+    elementsList,
+    isPending,
+    handleChangeName,
+    handleChangeDescription,
+    handleChangeType,
+    handleChangeGroup,
+    handleChangeElementsList,
+    handleSubmit,
+    updateUserOverlayForm,
+    handleChangeUploadedFile,
+    handleChangeOverlayContent,
+  } = useUserOverlayForm();
+
+  const navigateToOverlays = (): void => {
+    dispatch(openOverlaysDrawer());
+  };
+
+  return (
+    <>
+      <DrawerHeadingBackwardButton backwardFunction={navigateToOverlays}>
+        Add overlay
+      </DrawerHeadingBackwardButton>
+      <form className="flex h-[calc(100%-93px)] max-h-[calc(100%-93px)] flex-col overflow-y-auto p-6">
+        <div className="mb-2.5">
+          <p className="mb-2.5 text-sm">Upload file</p>
+          <FileUpload
+            uploadedFile={uploadedFile}
+            updateUserOverlayForm={updateUserOverlayForm}
+            handleChangeFile={handleChangeUploadedFile}
+            handleChangeOverlayContent={handleChangeOverlayContent}
+          />
+          <p className="my-5 text-center">or</p>
+          <label className="text-sm" htmlFor="elementsList">
+            Provide list of elements here
+            <Textarea
+              id="elementsList"
+              name="elementsList"
+              data-testid="overlay-elements-list"
+              value={elementsList}
+              onChange={handleChangeElementsList}
+              rows={6}
+              placeholder="Type here"
+              className="mt-2.5"
+            />
+          </label>
+        </div>
+
+        <label className="mb-2.5 text-sm" htmlFor="name">
+          Name
+          <Input
+            type="text"
+            name="name"
+            id="name"
+            data-testid="overlay-name"
+            value={name}
+            onChange={handleChangeName}
+            placeholder="Overlays 11/07/2022"
+            sizeVariant="medium"
+            className="mt-2.5 text-xs"
+          />
+        </label>
+
+        <OverlaySelector
+          value={type}
+          onChange={handleChangeType}
+          items={OVERLAY_TYPES}
+          label="Type"
+        />
+
+        <OverlaySelector
+          value={group}
+          onChange={handleChangeGroup}
+          items={OVERLAY_GROUPS}
+          label="Select group"
+        />
+
+        <label className="mt-2.5 text-sm" htmlFor="description">
+          Description
+          <Textarea
+            id="description"
+            name="description"
+            value={description}
+            data-testid="overlay-description"
+            onChange={handleChangeDescription}
+            rows={4}
+            placeholder="Type Description"
+            className="mt-2.5"
+          />
+        </label>
+        <Button
+          className="mt-2.5 items-center justify-center self-start"
+          onClick={handleSubmit}
+          disabled={isPending}
+          aria-label="upload overlay"
+        >
+          Upload
+        </Button>
+      </form>
+    </>
+  );
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.constants.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.constants.ts
new file mode 100644
index 00000000..3b4622db
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.constants.ts
@@ -0,0 +1,22 @@
+/* eslint-disable no-magic-numbers */
+export const OVERLAY_TYPES = [
+  {
+    id: 'GENERIC',
+    label: 'GENERIC',
+  },
+  {
+    id: 'GENETIC_VARIANT',
+    label: 'GENETIC_VARIANT',
+  },
+];
+
+export const OVERLAY_GROUPS = [
+  {
+    id: 'WITHOUT_GROUP',
+    label: 'Without group',
+  },
+];
+
+export const DEFAULT_GROUP = OVERLAY_GROUPS[0];
+
+export const DEFAULT_TYPE = OVERLAY_TYPES[0];
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.types.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.types.ts
new file mode 100644
index 00000000..531a4e20
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.types.ts
@@ -0,0 +1 @@
+export type SelectorItem = { id: string; label: string };
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.utils.test.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.utils.test.ts
new file mode 100644
index 00000000..9f3baf2a
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.utils.test.ts
@@ -0,0 +1,29 @@
+/* eslint-disable no-magic-numbers */
+import { processOverlayContentChange } from './UserOverlayForm.utils';
+
+const handleOverlayChange = jest.fn();
+
+describe('processOverlayContentChange', () => {
+  beforeEach(() => {
+    jest.clearAllMocks();
+  });
+
+  it('should parse overlay file content and invoke the handleOverlayChange callback for valid lines', () => {
+    const fileContent = `#NAME = John\n# DESCRIPTION = Some description\n# TYPE = Type1\n`;
+
+    processOverlayContentChange(fileContent, handleOverlayChange);
+
+    expect(handleOverlayChange).toHaveBeenCalledTimes(3);
+    expect(handleOverlayChange).toHaveBeenCalledWith('NAME', 'John');
+    expect(handleOverlayChange).toHaveBeenCalledWith('DESCRIPTION', 'Some description');
+    expect(handleOverlayChange).toHaveBeenCalledWith('TYPE', 'Type1');
+  });
+
+  it('should handle lines with invalid format without calling handleOverlayChange', () => {
+    const fileContent = `InvalidLine1\n#InvalidLine2\n=InvalidLine3\n`;
+
+    processOverlayContentChange(fileContent, handleOverlayChange);
+
+    expect(handleOverlayChange).not.toHaveBeenCalled();
+  });
+});
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.utils.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.utils.ts
new file mode 100644
index 00000000..e3c49999
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.utils.ts
@@ -0,0 +1,27 @@
+/* eslint-disable no-magic-numbers */
+
+type OverlayDataCallback = {
+  (nameType: string, value: string): void;
+};
+
+const OVERLAY_INFO_INDICATOR = '#';
+const ASSIGNMENT_OPERATOR = '=';
+
+export const processOverlayContentChange = (
+  fileContent: string,
+  callback: OverlayDataCallback,
+): void => {
+  const content = fileContent.trim();
+  const lines = content.split('\n');
+
+  lines.forEach(line => {
+    const isOverlayInfoLine = line.indexOf(OVERLAY_INFO_INDICATOR) === 0;
+    const hasAssignment = line.indexOf(ASSIGNMENT_OPERATOR) > 0;
+
+    if (isOverlayInfoLine && hasAssignment) {
+      const nameType = line.substring(1, line.indexOf(ASSIGNMENT_OPERATOR)).trim();
+      const value = line.substring(line.indexOf(ASSIGNMENT_OPERATOR) + 1).trim();
+      callback(nameType, value);
+    }
+  });
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/hooks/useUserOverlayForm.test.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/hooks/useUserOverlayForm.test.ts
new file mode 100644
index 00000000..988e9ea0
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/hooks/useUserOverlayForm.test.ts
@@ -0,0 +1,59 @@
+import { renderHook } from '@testing-library/react';
+import { act } from 'react-dom/test-utils';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { ChangeEvent } from 'react';
+import { useUserOverlayForm } from './useUserOverlayForm';
+
+describe('useUserOverlayForm', () => {
+  it('should update state when form fields are changed', () => {
+    const { Wrapper } = getReduxWrapperWithStore();
+    const { result } = renderHook(() => useUserOverlayForm(), { wrapper: Wrapper });
+
+    act(() => {
+      result.current.handleChangeType({ id: '1', label: 'Test Type' });
+      result.current.handleChangeGroup({ id: '1', label: 'Test Group' });
+    });
+
+    expect(result.current.type).toEqual({ id: '1', label: 'Test Type' });
+    expect(result.current.group).toEqual({ id: '1', label: 'Test Group' });
+  });
+
+  it('should update overlayContent when handleChangeOverlayContent is called', () => {
+    const { Wrapper } = getReduxWrapperWithStore();
+    const { result } = renderHook(() => useUserOverlayForm(), { wrapper: Wrapper });
+
+    act(() => {
+      result.current.handleChangeOverlayContent('Test Overlay Content');
+    });
+
+    expect(result.current.overlayContent).toBe('Test Overlay Content');
+  });
+  it('should update elementsList and overlayContent when handleChangeElementsList is called', () => {
+    const { Wrapper } = getReduxWrapperWithStore();
+    const { result } = renderHook(() => useUserOverlayForm(), { wrapper: Wrapper });
+
+    act(() => {
+      result.current.handleChangeElementsList({
+        target: { value: 'Test Elements List' },
+      } as ChangeEvent<HTMLTextAreaElement>);
+    });
+
+    expect(result.current.elementsList).toBe('Test Elements List');
+    expect(result.current.overlayContent).toBe('Test Elements List');
+  });
+  it('should update state variables based on updateUserOverlayForm', () => {
+    const { Wrapper } = getReduxWrapperWithStore();
+    const { result } = renderHook(() => useUserOverlayForm(), { wrapper: Wrapper });
+
+    act(() => {
+      result.current.updateUserOverlayForm('NAME', 'Test Name');
+    });
+
+    expect(result.current.name).toBe('Test Name');
+
+    act(() => {
+      result.current.updateUserOverlayForm('DESCRIPTION', 'Test Description');
+    });
+    expect(result.current.description).toBe('Test Description');
+  });
+});
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/hooks/useUserOverlayForm.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/hooks/useUserOverlayForm.ts
new file mode 100644
index 00000000..dda281bf
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/hooks/useUserOverlayForm.ts
@@ -0,0 +1,143 @@
+import { useState, ChangeEvent } from 'react';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { projectIdSelector } from '@/redux/project/project.selectors';
+import { addOverlay } from '@/redux/overlays/overlays.thunks';
+import { loadingAddOverlay } from '@/redux/overlays/overlays.selectors';
+import { DEFAULT_GROUP, DEFAULT_TYPE, OVERLAY_TYPES } from '../UserOverlayForm.constants';
+import { SelectorItem } from '../UserOverlayForm.types';
+import { processOverlayContentChange } from '../UserOverlayForm.utils';
+
+type ReturnType = {
+  name: string;
+  type: SelectorItem;
+  group: SelectorItem;
+  description: string;
+  uploadedFile: File | null;
+  elementsList: string;
+  overlayContent: string;
+  projectId?: string;
+  isPending: boolean;
+  handleChangeName: (e: ChangeEvent<HTMLInputElement>) => void;
+  handleChangeDescription: (e: ChangeEvent<HTMLTextAreaElement>) => void;
+  handleChangeType: (value: SelectorItem) => void;
+  handleChangeGroup: (value: SelectorItem) => void;
+  handleChangeUploadedFile: (value: File) => void;
+  handleChangeOverlayContent: (value: string) => void;
+  handleChangeElementsList: (e: ChangeEvent<HTMLTextAreaElement>) => void;
+  handleSubmit: () => Promise<void>;
+  updateUserOverlayForm: (nameType: string, value: string) => void;
+};
+
+export const useUserOverlayForm = (): ReturnType => {
+  const dispatch = useAppDispatch();
+  const projectId = useAppSelector(projectIdSelector);
+  const loadingAddOverlayStatus = useAppSelector(loadingAddOverlay);
+  const isPending = loadingAddOverlayStatus === 'pending';
+
+  const [name, setName] = useState('');
+  const [type, setType] = useState<SelectorItem>(DEFAULT_TYPE);
+  const [group, setGroup] = useState<SelectorItem>(DEFAULT_GROUP);
+  const [description, setDescription] = useState('');
+  const [uploadedFile, setUploadedFile] = useState<File | null>(null);
+  const [elementsList, setElementsList] = useState('');
+  const [overlayContent, setOverlayContent] = useState('');
+
+  const handleChangeName = (e: ChangeEvent<HTMLInputElement>): void => {
+    setName(e.target.value);
+  };
+
+  const handleChangeDescription = (e: ChangeEvent<HTMLTextAreaElement>): void => {
+    setDescription(e.target.value);
+  };
+
+  const handleChangeType = (value: SelectorItem): void => {
+    setType(value);
+  };
+
+  const handleChangeGroup = (value: SelectorItem): void => {
+    setGroup(value);
+  };
+
+  const handleChangeUploadedFile = (value: File): void => {
+    setUploadedFile(value);
+  };
+
+  const handleChangeOverlayContent = (value: string): void => {
+    setOverlayContent(value);
+  };
+
+  const updateUserOverlayForm = (nameType: string, value: string): void => {
+    switch (nameType) {
+      case 'NAME':
+        setName(value);
+        break;
+      case 'DESCRIPTION':
+        setDescription(value);
+        break;
+      case 'TYPE': {
+        const foundType = OVERLAY_TYPES.find(el => el.id === value);
+        if (foundType) {
+          setType(foundType);
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  };
+
+  const handleChangeElementsList = (e: ChangeEvent<HTMLTextAreaElement>): void => {
+    processOverlayContentChange(e.target.value, updateUserOverlayForm); // When user change elements list we have to analyze content. If it contains overlay info like e.g NAME we need to update field NAME in form
+    setOverlayContent(e.target.value);
+    setElementsList(e.target.value);
+  };
+
+  const handleSubmit = async (): Promise<void> => {
+    let filename = uploadedFile?.name;
+
+    if (!filename) {
+      filename = 'unknown.txt'; // Elements list is sent to the backend as a file, so we need to create a filename for the elements list.
+    }
+
+    if (!overlayContent || !projectId || !description || !name) return;
+
+    dispatch(
+      addOverlay({
+        content: overlayContent,
+        description,
+        filename,
+        name,
+        projectId,
+        type: type.id,
+      }),
+    );
+
+    setName('');
+    setDescription('');
+    setElementsList('');
+    setOverlayContent('');
+    setUploadedFile(null);
+  };
+
+  return {
+    name,
+    type,
+    group,
+    description,
+    uploadedFile,
+    elementsList,
+    overlayContent,
+    projectId,
+    isPending,
+    handleChangeName,
+    handleChangeDescription,
+    handleChangeType,
+    handleChangeGroup,
+    handleChangeElementsList,
+    handleSubmit,
+    updateUserOverlayForm,
+    handleChangeUploadedFile,
+    handleChangeOverlayContent,
+  };
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/index.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/index.ts
new file mode 100644
index 00000000..e51db0f0
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/index.ts
@@ -0,0 +1 @@
+export { UserOverlayForm } from './UserOverlayForm.component';
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.test.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.test.tsx
new file mode 100644
index 00000000..fbf7dc2e
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.test.tsx
@@ -0,0 +1,83 @@
+import { StoreType } from '@/redux/store';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { render, screen } from '@testing-library/react';
+import { UserOverlays } from './UserOverlays.component';
+
+const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
+  return (
+    render(
+      <Wrapper>
+        <UserOverlays />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('UserOverlays component', () => {
+  it('renders loading message when user is loading', () => {
+    renderComponent({
+      user: {
+        loading: 'pending',
+        authenticated: false,
+        error: { name: '', message: '' },
+        login: null,
+      },
+    });
+
+    expect(screen.getByText('Loading')).toBeInTheDocument();
+  });
+
+  it('renders login button when user is not authenticated', () => {
+    renderComponent({
+      user: {
+        loading: 'failed',
+        authenticated: false,
+        error: { name: '', message: '' },
+        login: null,
+      },
+    });
+
+    expect(screen.getByLabelText('login button')).toBeInTheDocument();
+  });
+
+  it('dispatches openLoginModal action when Login button is clicked', () => {
+    const { store } = renderComponent({
+      user: {
+        loading: 'failed',
+        authenticated: false,
+        error: { name: '', message: '' },
+        login: null,
+      },
+      modal: {
+        isOpen: false,
+        modalName: 'none',
+        modalTitle: '',
+        overviewImagesState: {},
+      },
+    });
+    screen.getByLabelText('login button').click();
+    const state = store.getState().modal;
+    expect(state.isOpen).toEqual(true);
+    expect(state.modalName).toEqual('login');
+  });
+
+  it('renders add overlay button when user is authenticated', () => {
+    renderComponent({
+      user: {
+        loading: 'succeeded',
+        authenticated: true,
+        error: { name: '', message: '' },
+        login: 'test',
+      },
+    });
+
+    expect(screen.getByLabelText('add overlay button')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.tsx
index d594f016..2db18b42 100644
--- a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.tsx
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.tsx
@@ -1,3 +1,4 @@
+import { displayAddOverlaysDrawer } from '@/redux/drawer/drawer.slice';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { openLoginModal } from '@/redux/modal/modal.slice';
@@ -8,27 +9,40 @@ export const UserOverlays = (): JSX.Element => {
   const dispatch = useAppDispatch();
   const loadingUser = useAppSelector(loadingUserSelector);
   const authenticatedUser = useAppSelector(authenticatedUserSelector);
+  const isPending = loadingUser === 'pending';
 
   const handleLoginClick = (): void => {
     dispatch(openLoginModal());
   };
 
+  const handleAddOverlay = (): void => {
+    dispatch(displayAddOverlaysDrawer());
+  };
+
   return (
     <div className="p-6">
-      {loadingUser === 'pending' && <h1>Loading</h1>}
+      {isPending && <h1>Loading</h1>}
 
-      {loadingUser !== 'pending' && !authenticatedUser && (
+      {!isPending && !authenticatedUser && (
         <>
           <p className="mb-5 font-semibold">User provided overlays:</p>
           <p className="mb-5 text-sm">
             You are not logged in, please login to upload and view custom overlays
           </p>
-          <Button onClick={handleLoginClick}>Login</Button>
+          <Button onClick={handleLoginClick} aria-label="login button">
+            Login
+          </Button>
         </>
       )}
 
-      {/* TODO: Implement user overlays */}
-      {authenticatedUser && <h1>Authenticated</h1>}
+      {authenticatedUser && (
+        <div className="flex items-center justify-between">
+          <p>User provided overlays:</p>
+          <Button onClick={handleAddOverlay} aria-label="add overlay button">
+            Add overlay
+          </Button>
+        </div>
+      )}
     </div>
   );
 };
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx
index bc8a61dd..b16f5069 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx
@@ -1,6 +1,6 @@
+import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture';
 import { MODELS_MOCK } from '@/models/mocks/modelsMock';
 import { StoreType } from '@/redux/store';
-import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture';
 import { Accordion } from '@/shared/Accordion';
 import {
   InitialStoreState,
@@ -73,7 +73,7 @@ describe('BioEntitiesAccordion - component', () => {
     });
 
     expect(screen.getByText('Content (10)')).toBeInTheDocument();
-    expect(screen.getByText('Core PD map (4)')).toBeInTheDocument();
-    expect(screen.getByText('Histamine signaling (1)')).toBeInTheDocument();
+    expect(screen.getByText('Core PD map (3)')).toBeInTheDocument();
+    expect(screen.getByText('Histamine signaling (5)')).toBeInTheDocument();
   });
 });
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/ResultsList.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/ResultsList.component.test.tsx
index a533a5b8..94bc618d 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/ResultsList.component.test.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/ResultsList.component.test.tsx
@@ -26,6 +26,9 @@ const INITIAL_STATE: InitialStoreState = {
     },
     reactionDrawerState: {},
     bioEntityDrawerState: {},
+    overlayDrawerState: {
+      currentStep: 0,
+    },
   },
   drugs: {
     data: [
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.test.tsx
index 9477d59d..c36eb3a9 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.test.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.test.tsx
@@ -45,6 +45,9 @@ describe('SearchDrawerWrapper - component', () => {
         },
         reactionDrawerState: {},
         bioEntityDrawerState: {},
+        overlayDrawerState: {
+          currentStep: 0,
+        },
       },
     });
 
@@ -65,6 +68,9 @@ describe('SearchDrawerWrapper - component', () => {
         },
         reactionDrawerState: {},
         bioEntityDrawerState: {},
+        overlayDrawerState: {
+          currentStep: 0,
+        },
       },
     });
 
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayGeometryFeature.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayGeometryFeature.ts
index 90887721..9f27f856 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayGeometryFeature.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayGeometryFeature.ts
@@ -1,13 +1,19 @@
-import { Fill, Style } from 'ol/style';
+import { Fill, Stroke, Style } from 'ol/style';
 import { fromExtent } from 'ol/geom/Polygon';
 import Feature from 'ol/Feature';
 import type Polygon from 'ol/geom/Polygon';
 
+const createFeatureFromExtent = ([xMin, yMin, xMax, yMax]: number[]): Feature<Polygon> =>
+  new Feature({ geometry: fromExtent([xMin, yMin, xMax, yMax]) });
+
+const getBioEntityOverlayFeatureStyle = (color: string): Style =>
+  new Style({ fill: new Fill({ color }), stroke: new Stroke({ color: 'black', width: 1 }) });
+
 export const createOverlayGeometryFeature = (
   [xMin, yMin, xMax, yMax]: number[],
   color: string,
 ): Feature<Polygon> => {
-  const feature = new Feature({ geometry: fromExtent([xMin, yMin, xMax, yMax]) });
-  feature.setStyle(new Style({ fill: new Fill({ color }) }));
+  const feature = createFeatureFromExtent([xMin, yMin, xMax, yMax]);
+  feature.setStyle(getBioEntityOverlayFeatureStyle(color));
   return feature;
 };
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayFeatures.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayFeatures.ts
index a2a7fb43..45723ea8 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayFeatures.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayFeatures.ts
@@ -3,14 +3,18 @@ import { OverlayBioEntityRender } from '@/types/OLrendering';
 import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
 import type Feature from 'ol/Feature';
 import type Polygon from 'ol/geom/Polygon';
+import { OverlayOrder } from '@/redux/overlayBioEntity/overlayBioEntity.utils';
+import { ZERO } from '@/constants/common';
 import { createOverlayGeometryFeature } from './createOverlayGeometryFeature';
 import { getColorByAvailableProperties } from './getColorByAvailableProperties';
+import { getPolygonLatitudeCoordinates } from './getPolygonLatitudeCoordinates';
 
 type GetOverlayFeaturesProps = {
   bioEntities: OverlayBioEntityRender[];
   pointToProjection: UsePointToProjectionResult;
   getHex3ColorGradientColorWithAlpha: GetHex3ColorGradientColorWithAlpha;
   defaultColor: string;
+  overlaysOrder: OverlayOrder[];
 };
 
 export const getOverlayFeatures = ({
@@ -18,13 +22,27 @@ export const getOverlayFeatures = ({
   pointToProjection,
   getHex3ColorGradientColorWithAlpha,
   defaultColor,
+  overlaysOrder,
 }: GetOverlayFeaturesProps): Feature<Polygon>[] =>
-  bioEntities.map(entity =>
-    createOverlayGeometryFeature(
+  bioEntities.map(entity => {
+    /**
+     * Depending on number of active overlays
+     * it's required to calculate xMin and xMax coordinates of the polygon
+     * so "entity" might be devided equali between active overlays
+     */
+    const { xMin, xMax } = getPolygonLatitudeCoordinates({
+      width: entity.width,
+      nOverlays: overlaysOrder.length,
+      xMin: entity.x1,
+      overlayIndexBasedOnOrder:
+        overlaysOrder.find(({ id }) => id === entity.overlayId)?.index || ZERO,
+    });
+
+    return createOverlayGeometryFeature(
       [
-        ...pointToProjection({ x: entity.x1, y: entity.y1 }),
-        ...pointToProjection({ x: entity.x2, y: entity.y2 }),
+        ...pointToProjection({ x: xMin, y: entity.y1 }),
+        ...pointToProjection({ x: xMax, y: entity.y2 }),
       ],
       getColorByAvailableProperties(entity, getHex3ColorGradientColorWithAlpha, defaultColor),
-    ),
-  );
+    );
+  });
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getPolygonLatitudeCoordinates.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getPolygonLatitudeCoordinates.test.ts
new file mode 100644
index 00000000..abb97f15
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/getPolygonLatitudeCoordinates.test.ts
@@ -0,0 +1,40 @@
+import { getPolygonLatitudeCoordinates } from './getPolygonLatitudeCoordinates';
+
+describe('getPolygonLatitudeCoordinates', () => {
+  const cases = [
+    {
+      width: 80,
+      nOverlays: 3,
+      xMin: 2137.5,
+      overlayIndexBasedOnOrder: 2,
+      expected: { xMin: 2190.83, xMax: 2217.5 },
+    },
+    {
+      width: 120,
+      nOverlays: 6,
+      xMin: 2137.5,
+      overlayIndexBasedOnOrder: 5,
+      expected: { xMin: 2237.5, xMax: 2257.5 },
+    },
+    {
+      width: 40,
+      nOverlays: 1,
+      xMin: 2137.5,
+      overlayIndexBasedOnOrder: 0,
+      expected: { xMin: 2137.5, xMax: 2177.5 },
+    },
+  ];
+
+  it.each(cases)(
+    'should return the correct latitude coordinates for width=$width, nOverlays=$nOverlays, xMin=$xMin, and overlayIndexBasedOnOrder=$overlayIndexBasedOnOrder',
+    ({ width, nOverlays, xMin, overlayIndexBasedOnOrder, expected }) => {
+      const result = getPolygonLatitudeCoordinates({
+        width,
+        nOverlays,
+        xMin,
+        overlayIndexBasedOnOrder,
+      });
+      expect(result).toEqual(expected);
+    },
+  );
+});
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getPolygonLatitudeCoordinates.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getPolygonLatitudeCoordinates.ts
new file mode 100644
index 00000000..bd997739
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/getPolygonLatitudeCoordinates.ts
@@ -0,0 +1,26 @@
+import { roundToTwoDigits } from '@/utils/number/roundToTwoDigits';
+
+type GetLatitudeCoordinatesProps = {
+  width: number;
+  nOverlays: number;
+  /** bottom left corner of entity drawn on the map */
+  xMin: number;
+  overlayIndexBasedOnOrder: number;
+};
+
+type PolygonLatitudeCoordinates = {
+  xMin: number;
+  xMax: number;
+};
+
+export const getPolygonLatitudeCoordinates = ({
+  width,
+  nOverlays,
+  xMin,
+  overlayIndexBasedOnOrder,
+}: GetLatitudeCoordinatesProps): PolygonLatitudeCoordinates => {
+  const polygonWidth = width / nOverlays;
+  const newXMin = xMin + polygonWidth * overlayIndexBasedOnOrder;
+  const xMax = newXMin + polygonWidth;
+  return { xMin: roundToTwoDigits(newXMin), xMax: roundToTwoDigits(xMax) };
+};
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOlMapOverlaysLayer.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOlMapOverlaysLayer.ts
index 048fecd7..50be44c0 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOlMapOverlaysLayer.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOlMapOverlaysLayer.ts
@@ -1,17 +1,37 @@
 import { useTriColorLerp } from '@/hooks/useTriColorLerp';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
-import { overlayBioEntitiesForCurrentModelSelector } from '@/redux/overlayBioEntity/overlayBioEntity.selector';
+import {
+  getOverlayOrderSelector,
+  overlayBioEntitiesForCurrentModelSelector,
+} from '@/redux/overlayBioEntity/overlayBioEntity.selector';
 import { usePointToProjection } from '@/utils/map/usePointToProjection';
-import { Polygon } from 'ol/geom';
+import { Geometry } from 'ol/geom';
 import VectorLayer from 'ol/layer/Vector';
 import VectorSource from 'ol/source/Vector';
 import { useMemo } from 'react';
+
+import { Feature } from 'ol';
 import { getOverlayFeatures } from './getOverlayFeatures';
 
-export const useOlMapOverlaysLayer = (): VectorLayer<VectorSource<Polygon>> => {
+/**
+ * Prerequisites: "view" button triggers opening overlays -> it triggers downloading overlayBioEntityData for given overlay for ALL available submaps(models)
+ *
+ * 1. For each active overlay
+ * 2. get overlayBioEntity data (current map data passed by selector)
+ * 3. based on nOverlays, calculate coordinates for given overlayBioEntity to render Polygon from extend
+ * 4. Calculate coordinates in following steps:
+ *   - polygonWidth = width/nOverlays
+ *   - xMin = xMin + polygonWidth * overlayIndexBasedOnOrder
+ *   - xMax = xMin + polygonWidth
+ *   - yMin,yMax -> is const taken from store
+ * 5. generate Feature(xMin,yMin,xMax,yMax)
+ */
+
+export const useOlMapOverlaysLayer = (): VectorLayer<VectorSource<Feature<Geometry>>> => {
   const pointToProjection = usePointToProjection();
   const { getHex3ColorGradientColorWithAlpha, defaultColorHex } = useTriColorLerp();
   const bioEntities = useAppSelector(overlayBioEntitiesForCurrentModelSelector);
+  const overlaysOrder = useAppSelector(getOverlayOrderSelector);
 
   const features = useMemo(
     () =>
@@ -20,8 +40,15 @@ export const useOlMapOverlaysLayer = (): VectorLayer<VectorSource<Polygon>> => {
         pointToProjection,
         getHex3ColorGradientColorWithAlpha,
         defaultColor: defaultColorHex,
+        overlaysOrder,
       }),
-    [bioEntities, getHex3ColorGradientColorWithAlpha, pointToProjection, defaultColorHex],
+    [
+      bioEntities,
+      getHex3ColorGradientColorWithAlpha,
+      pointToProjection,
+      defaultColorHex,
+      overlaysOrder,
+    ],
   );
 
   const vectorSource = useMemo(() => {
diff --git a/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts b/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
index 3722f302..37bb871b 100644
--- a/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
+++ b/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
@@ -4,6 +4,7 @@ import { allReactionsSelectorOfCurrentMap } from '@/redux/reactions/reactions.se
 import { Reaction } from '@/types/models';
 import { LinePoint } from '@/types/reactions';
 import { usePointToProjection } from '@/utils/map/usePointToProjection';
+import { Feature } from 'ol';
 import { Geometry } from 'ol/geom';
 import VectorLayer from 'ol/layer/Vector';
 import VectorSource from 'ol/source/Vector';
@@ -17,7 +18,7 @@ import { getLineFeature } from './getLineFeature';
 const getReactionsLines = (reactions: Reaction[]): LinePoint[] =>
   reactions.map(({ lines }) => lines.map(({ start, end }): LinePoint => [start, end])).flat();
 
-export const useOlMapReactionsLayer = (): VectorLayer<VectorSource<Geometry>> => {
+export const useOlMapReactionsLayer = (): VectorLayer<VectorSource<Feature<Geometry>>> => {
   const pointToProjection = usePointToProjection();
   const reactions = useSelector(allReactionsSelectorOfCurrentMap);
   const reactionsLines = getReactionsLines(reactions);
diff --git a/src/models/bioEntitySchema.ts b/src/models/bioEntitySchema.ts
index 9014bc87..5a66d612 100644
--- a/src/models/bioEntitySchema.ts
+++ b/src/models/bioEntitySchema.ts
@@ -1,13 +1,13 @@
 import { z } from 'zod';
-import { referenceSchema } from './referenceSchema';
-import { glyphSchema } from './glyphSchema';
-import { modificationResiduesSchema } from './modificationResiduesSchema';
-import { submodelSchema } from './submodelSchema';
 import { colorSchema } from './colorSchema';
-import { productsSchema } from './products';
+import { glyphSchema } from './glyphSchema';
 import { lineSchema } from './lineSchema';
+import { modificationResiduesSchema } from './modificationResiduesSchema';
 import { operatorSchema } from './operatorSchema';
+import { productsSchema } from './products';
+import { referenceSchema } from './referenceSchema';
 import { structuralStateSchema } from './structuralStateSchema';
+import { submodelSchema } from './submodelSchema';
 
 export const bioEntitySchema = z.object({
   id: z.number(),
@@ -33,6 +33,7 @@ export const bioEntitySchema = z.object({
   synonyms: z.array(z.string()),
   formerSymbols: z.array(z.string()),
   fullName: z.string().nullable(),
+  compartmentName: z.string().nullable(),
   abbreviation: z.string().nullable(),
   formula: z.string().nullable(),
   glyph: glyphSchema.nullable(),
diff --git a/src/models/configurationSchema.ts b/src/models/configurationSchema.ts
new file mode 100644
index 00000000..db44bb56
--- /dev/null
+++ b/src/models/configurationSchema.ts
@@ -0,0 +1,105 @@
+import { z } from 'zod';
+
+export const elementTypeSchema = z.object({
+  className: z.string(),
+  name: z.string(),
+  parentClass: z.string(),
+});
+
+export const optionSchema = z.object({
+  idObject: z.number(),
+  type: z.string(),
+  valueType: z.string(),
+  commonName: z.string(),
+  isServerSide: z.boolean(),
+  group: z.string(),
+  value: z.string().optional(),
+});
+
+export const imageFormatSchema = z.object({
+  name: z.string(),
+  handler: z.string(),
+  extension: z.string(),
+});
+
+export const modelFormatSchema = z.object({
+  name: z.string(),
+  handler: z.string(),
+  extension: z.string(),
+});
+
+export const overlayTypeSchema = z.object({ name: z.string() });
+
+export const reactionTypeSchema = z.object({
+  className: z.string(),
+  name: z.string(),
+  parentClass: z.string(),
+});
+
+export const miriamTypesSchema = z.record(
+  z.string(),
+  z.object({
+    commonName: z.string(),
+    homepage: z.string().nullable(),
+    registryIdentifier: z.string().nullable(),
+    uris: z.array(z.string()),
+  }),
+);
+
+export const bioEntityFieldSchema = z.object({ commonName: z.string(), name: z.string() });
+
+export const annotatorSchema = z.object({
+  className: z.string(),
+  name: z.string(),
+  description: z.string(),
+  url: z.string(),
+  elementClassNames: z.array(z.string()),
+  parameters: z.array(
+    z.object({
+      field: z.string().nullable().optional(),
+      annotation_type: z.string().nullable().optional(),
+      order: z.number(),
+      type: z.string(),
+    }),
+  ),
+});
+
+export const privilegeTypeSchema = z.record(
+  z.string(),
+  z.object({
+    commonName: z.string(),
+    objectType: z.string().nullable(),
+    valueType: z.string(),
+  }),
+);
+
+export const mapTypeSchema = z.object({ name: z.string(), id: z.string() });
+
+export const mapCanvasTypeSchema = z.object({ name: z.string(), id: z.string() });
+
+export const unitTypeSchema = z.object({ name: z.string(), id: z.string() });
+
+export const modificationStateTypeSchema = z.record(
+  z.string(),
+  z.object({ commonName: z.string(), abbreviation: z.string() }),
+);
+
+export const configurationSchema = z.object({
+  elementTypes: z.array(elementTypeSchema),
+  options: z.array(optionSchema),
+  imageFormats: z.array(imageFormatSchema),
+  modelFormats: z.array(modelFormatSchema),
+  overlayTypes: z.array(overlayTypeSchema),
+  reactionTypes: z.array(reactionTypeSchema),
+  miriamTypes: miriamTypesSchema,
+  bioEntityFields: z.array(bioEntityFieldSchema),
+  version: z.string(),
+  buildDate: z.string(),
+  gitHash: z.string(),
+  annotators: z.array(annotatorSchema),
+  privilegeTypes: privilegeTypeSchema,
+  mapTypes: z.array(mapTypeSchema),
+  mapCanvasTypes: z.array(mapCanvasTypeSchema),
+  unitTypes: z.array(unitTypeSchema),
+  modificationStateTypes: modificationStateTypeSchema,
+});
diff --git a/src/models/fixtures/overlaysFixture.ts b/src/models/fixtures/overlaysFixture.ts
index c0a26efd..d981dba3 100644
--- a/src/models/fixtures/overlaysFixture.ts
+++ b/src/models/fixtures/overlaysFixture.ts
@@ -2,9 +2,25 @@ import { ZOD_SEED } from '@/constants';
 import { z } from 'zod';
 // eslint-disable-next-line import/no-extraneous-dependencies
 import { createFixture } from 'zod-fixture';
-import { mapOverlay } from '../mapOverlay';
+import {
+  createdOverlayFileSchema,
+  createdOverlaySchema,
+  mapOverlay,
+  uploadedOverlayFileContentSchema,
+} from '../mapOverlay';
 
 export const overlaysFixture = createFixture(z.array(mapOverlay), {
   seed: ZOD_SEED,
   array: { min: 2, max: 2 },
 });
+
+export const createdOverlayFileFixture = createFixture(createdOverlayFileSchema, {
+  seed: ZOD_SEED,
+});
+
+export const uploadedOverlayFileContentFixture = createFixture(uploadedOverlayFileContentSchema, {
+  seed: ZOD_SEED,
+});
+export const createdOverlayFixture = createFixture(createdOverlaySchema, {
+  seed: ZOD_SEED,
+});
diff --git a/src/models/fixtures/statisticsFixture.ts b/src/models/fixtures/statisticsFixture.ts
new file mode 100644
index 00000000..92500578
--- /dev/null
+++ b/src/models/fixtures/statisticsFixture.ts
@@ -0,0 +1,8 @@
+import { ZOD_SEED } from '@/constants';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { createFixture } from 'zod-fixture';
+import { statisticsSchema } from '../statisticsSchema';
+
+export const statisticsFixture = createFixture(statisticsSchema, {
+  seed: ZOD_SEED,
+});
diff --git a/src/models/mapOverlay.ts b/src/models/mapOverlay.ts
index a22b65aa..16da5717 100644
--- a/src/models/mapOverlay.ts
+++ b/src/models/mapOverlay.ts
@@ -12,3 +12,26 @@ export const mapOverlay = z.object({
   type: z.string(),
   order: z.number(),
 });
+
+export const createdOverlayFileSchema = z.object({
+  id: z.number(),
+  filename: z.string(),
+  length: z.number(),
+  owner: z.string(),
+  uploadedDataLength: z.number(),
+});
+
+export const uploadedOverlayFileContentSchema = createdOverlayFileSchema.extend({});
+
+export const createdOverlaySchema = z.object({
+  name: z.string(),
+  googleLicenseConsent: z.boolean(),
+  creator: z.string(),
+  description: z.string(),
+  genomeType: z.string().nullable(),
+  genomeVersion: z.string().nullable(),
+  idObject: z.number(),
+  publicOverlay: z.boolean(),
+  type: z.string(),
+  order: z.number(),
+});
diff --git a/src/models/statisticsSchema.ts b/src/models/statisticsSchema.ts
new file mode 100644
index 00000000..8cb37fac
--- /dev/null
+++ b/src/models/statisticsSchema.ts
@@ -0,0 +1,7 @@
+import { z } from 'zod';
+
+export const statisticsSchema = z.object({
+  elementAnnotations: z.record(z.string(), z.number()),
+  publications: z.number(),
+  reactionAnnotations: z.record(z.string(), z.number()),
+});
diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts
index cc657a71..433b6c49 100644
--- a/src/redux/apiPath.ts
+++ b/src/redux/apiPath.ts
@@ -32,6 +32,11 @@ export const apiPath = {
   getSessionValid: (): string => `users/isSessionValid`,
   postLogin: (): string => `doLogin`,
   getConfigurationOptions: (): string => 'configuration/options/',
+  getConfiguration: (): string => 'configuration/',
   getOverlayBioEntity: ({ overlayId, modelId }: { overlayId: number; modelId: number }): string =>
     `projects/${PROJECT_ID}/overlays/${overlayId}/models/${modelId}/bioEntities/`,
+  createOverlay: (projectId: string): string => `projects/${projectId}/overlays/`,
+  createOverlayFile: (): string => `files/`,
+  uploadOverlayFileContent: (fileId: number): string => `files/${fileId}:uploadContent`,
+  getStatisticsById: (projectId: string): string => `projects/${projectId}/statistics/`,
 };
diff --git a/src/redux/configuration/configuration.adapter.ts b/src/redux/configuration/configuration.adapter.ts
index cb3c59be..d99fb14c 100644
--- a/src/redux/configuration/configuration.adapter.ts
+++ b/src/redux/configuration/configuration.adapter.ts
@@ -2,6 +2,7 @@ import { DEFAULT_ERROR } from '@/constants/errors';
 import { Loading } from '@/types/loadingState';
 import { ConfigurationOption } from '@/types/models';
 import { createEntityAdapter } from '@reduxjs/toolkit';
+import { ConfigurationMainState } from './configuration.types';
 
 export const configurationAdapter = createEntityAdapter<ConfigurationOption>({
   selectId: option => option.type,
@@ -12,7 +13,14 @@ const REQUEST_INITIAL_STATUS: { loading: Loading; error: Error } = {
   error: DEFAULT_ERROR,
 };
 
-export const CONFIGURATION_INITIAL_STATE =
-  configurationAdapter.getInitialState(REQUEST_INITIAL_STATUS);
+const MAIN_CONFIGURATION_INITIAL_STATE: ConfigurationMainState = {
+  data: undefined,
+  ...REQUEST_INITIAL_STATUS,
+};
+
+export const CONFIGURATION_INITIAL_STATE = {
+  options: configurationAdapter.getInitialState(REQUEST_INITIAL_STATUS),
+  main: MAIN_CONFIGURATION_INITIAL_STATE,
+};
 
 export type ConfigurationState = typeof CONFIGURATION_INITIAL_STATE;
diff --git a/src/redux/configuration/configuration.mock.ts b/src/redux/configuration/configuration.mock.ts
index ce8f052d..d3719904 100644
--- a/src/redux/configuration/configuration.mock.ts
+++ b/src/redux/configuration/configuration.mock.ts
@@ -7,21 +7,35 @@ import {
 import { ConfigurationState } from './configuration.adapter';
 
 export const CONFIGURATION_INITIAL_STORE_MOCK: ConfigurationState = {
-  ids: [],
-  entities: {},
-  loading: 'idle',
-  error: DEFAULT_ERROR,
+  options: {
+    ids: [],
+    entities: {},
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
+  main: {
+    data: undefined,
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
 };
 
 /** IMPORTANT MOCK IDS MUST MATCH KEYS IN ENTITIES  */
 export const CONFIGURATION_INITIAL_STORE_MOCKS: ConfigurationState = {
-  ids: CONFIGURATION_OPTIONS_TYPES_MOCK,
-  entities: {
-    [CONFIGURATION_OPTIONS_TYPES_MOCK[0]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[0],
-    [CONFIGURATION_OPTIONS_TYPES_MOCK[1]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[1],
-    [CONFIGURATION_OPTIONS_TYPES_MOCK[2]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[2],
-    [CONFIGURATION_OPTIONS_TYPES_MOCK[3]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[3],
+  options: {
+    ids: CONFIGURATION_OPTIONS_TYPES_MOCK,
+    entities: {
+      [CONFIGURATION_OPTIONS_TYPES_MOCK[0]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[0],
+      [CONFIGURATION_OPTIONS_TYPES_MOCK[1]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[1],
+      [CONFIGURATION_OPTIONS_TYPES_MOCK[2]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[2],
+      [CONFIGURATION_OPTIONS_TYPES_MOCK[3]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[3],
+    },
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
+  main: {
+    data: undefined,
+    loading: 'idle',
+    error: DEFAULT_ERROR,
   },
-  loading: 'idle',
-  error: DEFAULT_ERROR,
 };
diff --git a/src/redux/configuration/configuration.reducers.ts b/src/redux/configuration/configuration.reducers.ts
index 01cd1fe5..57e60a05 100644
--- a/src/redux/configuration/configuration.reducers.ts
+++ b/src/redux/configuration/configuration.reducers.ts
@@ -1,21 +1,37 @@
 import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
-import { getConfigurationOptions } from './configuration.thunks';
+import { getConfiguration, getConfigurationOptions } from './configuration.thunks';
 import { ConfigurationState, configurationAdapter } from './configuration.adapter';
 
 export const getConfigurationOptionsReducer = (
   builder: ActionReducerMapBuilder<ConfigurationState>,
 ): void => {
   builder.addCase(getConfigurationOptions.pending, state => {
-    state.loading = 'pending';
+    state.options.loading = 'pending';
   });
   builder.addCase(getConfigurationOptions.fulfilled, (state, action) => {
     if (action.payload) {
-      state.loading = 'succeeded';
-      configurationAdapter.addMany(state, action.payload);
+      state.options.loading = 'succeeded';
+      configurationAdapter.addMany(state.options, action.payload);
     }
   });
   builder.addCase(getConfigurationOptions.rejected, state => {
-    state.loading = 'failed';
+    state.options.loading = 'failed';
+    // TODO to discuss manage state of failure
+  });
+};
+
+export const getConfigurationReducer = (
+  builder: ActionReducerMapBuilder<ConfigurationState>,
+): void => {
+  builder.addCase(getConfiguration.pending, state => {
+    state.main.loading = 'pending';
+  });
+  builder.addCase(getConfiguration.fulfilled, (state, action) => {
+    state.main.loading = 'succeeded';
+    state.main.data = action.payload;
+  });
+  builder.addCase(getConfiguration.rejected, state => {
+    state.main.loading = 'failed';
     // TODO to discuss manage state of failure
   });
 };
diff --git a/src/redux/configuration/configuration.selectors.ts b/src/redux/configuration/configuration.selectors.ts
index 2831a55f..3fc6d2e7 100644
--- a/src/redux/configuration/configuration.selectors.ts
+++ b/src/redux/configuration/configuration.selectors.ts
@@ -11,36 +11,47 @@ import {
 } from './configuration.constants';
 
 const configurationSelector = createSelector(rootSelector, state => state.configuration);
+const configurationOptionsSelector = createSelector(configurationSelector, state => state.options);
 
 const configurationAdapterSelectors = configurationAdapter.getSelectors();
 
 export const minColorValSelector = createSelector(
-  configurationSelector,
+  configurationOptionsSelector,
   state => configurationAdapterSelectors.selectById(state, MIN_COLOR_VAL_NAME_ID)?.value,
 );
 
 export const maxColorValSelector = createSelector(
-  configurationSelector,
+  configurationOptionsSelector,
   state => configurationAdapterSelectors.selectById(state, MAX_COLOR_VAL_NAME_ID)?.value,
 );
 
 export const neutralColorValSelector = createSelector(
-  configurationSelector,
+  configurationOptionsSelector,
   state => configurationAdapterSelectors.selectById(state, NEUTRAL_COLOR_VAL_NAME_ID)?.value,
 );
 
 export const overlayOpacitySelector = createSelector(
-  configurationSelector,
+  configurationOptionsSelector,
   state => configurationAdapterSelectors.selectById(state, OVERLAY_OPACITY_NAME_ID)?.value,
 );
 
 export const simpleColorValSelector = createSelector(
-  configurationSelector,
+  configurationOptionsSelector,
   state => configurationAdapterSelectors.selectById(state, SIMPLE_COLOR_VAL_NAME_ID)?.value,
 );
 
-export const defaultLegendImagesSelector = createSelector(configurationSelector, state =>
+export const defaultLegendImagesSelector = createSelector(configurationOptionsSelector, state =>
   LEGEND_FILE_NAMES_IDS.map(
     legendNameId => configurationAdapterSelectors.selectById(state, legendNameId)?.value,
   ).filter(legendImage => Boolean(legendImage)),
 );
+
+export const configurationMainSelector = createSelector(
+  configurationSelector,
+  state => state.main.data,
+);
+
+export const elementTypesSelector = createSelector(
+  configurationMainSelector,
+  state => state?.elementTypes,
+);
diff --git a/src/redux/configuration/configuration.slice.ts b/src/redux/configuration/configuration.slice.ts
index 4bf43488..7758564a 100644
--- a/src/redux/configuration/configuration.slice.ts
+++ b/src/redux/configuration/configuration.slice.ts
@@ -1,5 +1,5 @@
 import { createSlice } from '@reduxjs/toolkit';
-import { getConfigurationOptionsReducer } from './configuration.reducers';
+import { getConfigurationOptionsReducer, getConfigurationReducer } from './configuration.reducers';
 import { CONFIGURATION_INITIAL_STATE } from './configuration.adapter';
 
 export const configurationSlice = createSlice({
@@ -8,6 +8,7 @@ export const configurationSlice = createSlice({
   reducers: {},
   extraReducers: builder => {
     getConfigurationOptionsReducer(builder);
+    getConfigurationReducer(builder);
   },
 });
 
diff --git a/src/redux/configuration/configuration.thunks.ts b/src/redux/configuration/configuration.thunks.ts
index ad3812bb..012e8b1c 100644
--- a/src/redux/configuration/configuration.thunks.ts
+++ b/src/redux/configuration/configuration.thunks.ts
@@ -1,8 +1,9 @@
-import { ConfigurationOption } from '@/types/models';
+import { Configuration, ConfigurationOption } from '@/types/models';
 import { createAsyncThunk } from '@reduxjs/toolkit';
 import { z } from 'zod';
 import { axiosInstance } from '@/services/api/utils/axiosInstance';
 import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+import { configurationSchema } from '@/models/configurationSchema';
 import { configurationOptionSchema } from '@/models/configurationOptionSchema';
 import { apiPath } from '../apiPath';
 
@@ -21,3 +22,14 @@ export const getConfigurationOptions = createAsyncThunk(
     return isDataValid ? response.data : undefined;
   },
 );
+
+export const getConfiguration = createAsyncThunk(
+  'configuration/getConfiguration',
+  async (): Promise<Configuration | undefined> => {
+    const response = await axiosInstance.get<Configuration>(apiPath.getConfiguration());
+
+    const isDataValid = validateDataUsingZodSchema(response.data, configurationSchema);
+
+    return isDataValid ? response.data : undefined;
+  },
+);
diff --git a/src/redux/configuration/configuration.types.ts b/src/redux/configuration/configuration.types.ts
new file mode 100644
index 00000000..086619ae
--- /dev/null
+++ b/src/redux/configuration/configuration.types.ts
@@ -0,0 +1,4 @@
+import { FetchDataState } from '@/types/fetchDataState';
+import { Configuration } from '@/types/models';
+
+export type ConfigurationMainState = FetchDataState<Configuration>;
diff --git a/src/redux/drawer/drawer.constants.ts b/src/redux/drawer/drawer.constants.ts
index c04c0296..f1035f97 100644
--- a/src/redux/drawer/drawer.constants.ts
+++ b/src/redux/drawer/drawer.constants.ts
@@ -12,4 +12,7 @@ export const DRAWER_INITIAL_STATE: DrawerState = {
   },
   reactionDrawerState: {},
   bioEntityDrawerState: {},
+  overlayDrawerState: {
+    currentStep: 0,
+  },
 };
diff --git a/src/redux/drawer/drawer.reducers.ts b/src/redux/drawer/drawer.reducers.ts
index 8ecb8328..8a60b60f 100644
--- a/src/redux/drawer/drawer.reducers.ts
+++ b/src/redux/drawer/drawer.reducers.ts
@@ -31,6 +31,13 @@ export const openSubmapsDrawerReducer = (state: DrawerState): void => {
 export const openOverlaysDrawerReducer = (state: DrawerState): void => {
   state.isOpen = true;
   state.drawerName = 'overlays';
+  state.overlayDrawerState.currentStep = STEP.FIRST;
+};
+
+export const displayAddOverlaysDrawerReducer = (state: DrawerState): void => {
+  state.isOpen = true;
+  state.drawerName = 'overlays';
+  state.overlayDrawerState.currentStep = STEP.SECOND;
 };
 
 export const selectTabReducer = (
diff --git a/src/redux/drawer/drawer.selectors.ts b/src/redux/drawer/drawer.selectors.ts
index 060a652a..26e9a90b 100644
--- a/src/redux/drawer/drawer.selectors.ts
+++ b/src/redux/drawer/drawer.selectors.ts
@@ -98,3 +98,13 @@ export const currentDrawerReactionIdSelector = createSelector(
   reactionDrawerStateSelector,
   state => state?.reactionId,
 );
+
+export const overlayDrawerStateSelector = createSelector(
+  drawerSelector,
+  state => state.overlayDrawerState,
+);
+
+export const currentStepOverlayDrawerStateSelector = createSelector(
+  overlayDrawerStateSelector,
+  state => state.currentStep,
+);
diff --git a/src/redux/drawer/drawer.slice.ts b/src/redux/drawer/drawer.slice.ts
index 769b5cf0..98e073ae 100644
--- a/src/redux/drawer/drawer.slice.ts
+++ b/src/redux/drawer/drawer.slice.ts
@@ -13,6 +13,7 @@ import {
   openSearchDrawerWithSelectedTabReducer,
   openSubmapsDrawerReducer,
   selectTabReducer,
+  displayAddOverlaysDrawerReducer,
 } from './drawer.reducers';
 import { DRAWER_INITIAL_STATE } from './drawer.constants';
 
@@ -24,6 +25,7 @@ const drawerSlice = createSlice({
     openSearchDrawerWithSelectedTab: openSearchDrawerWithSelectedTabReducer,
     openSubmapsDrawer: openSubmapsDrawerReducer,
     openOverlaysDrawer: openOverlaysDrawerReducer,
+    displayAddOverlaysDrawer: displayAddOverlaysDrawerReducer,
     selectTab: selectTabReducer,
     closeDrawer: closeDrawerReducer,
     displayDrugsList: displayDrugsListReducer,
@@ -41,6 +43,7 @@ export const {
   openSearchDrawerWithSelectedTab,
   openSubmapsDrawer,
   openOverlaysDrawer,
+  displayAddOverlaysDrawer,
   selectTab,
   closeDrawer,
   displayDrugsList,
diff --git a/src/redux/drawer/drawer.types.ts b/src/redux/drawer/drawer.types.ts
index 44ed6516..075fcd19 100644
--- a/src/redux/drawer/drawer.types.ts
+++ b/src/redux/drawer/drawer.types.ts
@@ -10,6 +10,10 @@ export type SearchDrawerState = {
   selectedSearchElement: string;
 };
 
+export type OverlayDrawerState = {
+  currentStep: number;
+};
+
 export type ReactionDrawerState = {
   reactionId?: number;
 };
@@ -24,6 +28,7 @@ export type DrawerState = {
   searchDrawerState: SearchDrawerState;
   reactionDrawerState: ReactionDrawerState;
   bioEntityDrawerState: BioEntityDrawerState;
+  overlayDrawerState: OverlayDrawerState;
 };
 
 export type OpenSearchDrawerWithSelectedTabReducerPayload = string;
diff --git a/src/redux/drawer/drawerFixture.ts b/src/redux/drawer/drawerFixture.ts
index 818a545c..29b32d3a 100644
--- a/src/redux/drawer/drawerFixture.ts
+++ b/src/redux/drawer/drawerFixture.ts
@@ -12,6 +12,9 @@ export const initialStateFixture: DrawerState = {
   },
   reactionDrawerState: {},
   bioEntityDrawerState: {},
+  overlayDrawerState: {
+    currentStep: 0,
+  },
 };
 
 export const openedDrawerSubmapsFixture: DrawerState = {
@@ -26,6 +29,9 @@ export const openedDrawerSubmapsFixture: DrawerState = {
   },
   reactionDrawerState: {},
   bioEntityDrawerState: {},
+  overlayDrawerState: {
+    currentStep: 0,
+  },
 };
 
 export const drawerSearchStepOneFixture: DrawerState = {
@@ -40,6 +46,9 @@ export const drawerSearchStepOneFixture: DrawerState = {
   },
   reactionDrawerState: {},
   bioEntityDrawerState: {},
+  overlayDrawerState: {
+    currentStep: 0,
+  },
 };
 
 export const drawerSearchDrugsStepTwoFixture: DrawerState = {
@@ -54,6 +63,9 @@ export const drawerSearchDrugsStepTwoFixture: DrawerState = {
   },
   reactionDrawerState: {},
   bioEntityDrawerState: {},
+  overlayDrawerState: {
+    currentStep: 0,
+  },
 };
 
 export const drawerSearchChemicalsStepTwoFixture: DrawerState = {
@@ -68,4 +80,41 @@ export const drawerSearchChemicalsStepTwoFixture: DrawerState = {
   },
   reactionDrawerState: {},
   bioEntityDrawerState: {},
+  overlayDrawerState: {
+    currentStep: 0,
+  },
+};
+
+export const drawerOverlaysStepOneFixture: DrawerState = {
+  isOpen: true,
+  drawerName: 'overlays',
+  searchDrawerState: {
+    currentStep: 0,
+    stepType: 'none',
+    selectedValue: undefined,
+    listOfBioEnitites: [],
+    selectedSearchElement: '',
+  },
+  reactionDrawerState: {},
+  bioEntityDrawerState: {},
+  overlayDrawerState: {
+    currentStep: 2,
+  },
+};
+
+export const openedExportDrawerFixture: DrawerState = {
+  isOpen: true,
+  drawerName: 'export',
+  searchDrawerState: {
+    currentStep: 0,
+    stepType: 'none',
+    selectedValue: undefined,
+    listOfBioEnitites: [],
+    selectedSearchElement: '',
+  },
+  reactionDrawerState: {},
+  bioEntityDrawerState: {},
+  overlayDrawerState: {
+    currentStep: 0,
+  },
 };
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.selector.ts b/src/redux/overlayBioEntity/overlayBioEntity.selector.ts
index 00803c03..f3dbd72c 100644
--- a/src/redux/overlayBioEntity/overlayBioEntity.selector.ts
+++ b/src/redux/overlayBioEntity/overlayBioEntity.selector.ts
@@ -1,6 +1,9 @@
 import { createSelector } from '@reduxjs/toolkit';
+import { OverlayBioEntityRender } from '@/types/OLrendering';
 import { rootSelector } from '../root/root.selectors';
 import { currentModelIdSelector } from '../models/models.selectors';
+import { overlaysIdsAndOrderSelector } from '../overlays/overlays.selectors';
+import { calculateOvarlaysOrder } from './overlayBioEntity.utils';
 
 export const overlayBioEntitySelector = createSelector(
   rootSelector,
@@ -17,17 +20,36 @@ export const activeOverlaysIdSelector = createSelector(
   state => state.overlaysId,
 );
 
-const FIRST_ENTITY_INDEX = 0;
-// TODO, improve selector when multioverlay algorithm comes in place
 export const overlayBioEntitiesForCurrentModelSelector = createSelector(
   overlayBioEntityDataSelector,
+  activeOverlaysIdSelector,
   currentModelIdSelector,
-  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-  // @ts-ignore
-  (data, currentModelId) => data[Object.keys(data)[FIRST_ENTITY_INDEX]]?.[currentModelId] ?? [], // temporary solution untill multioverlay algorithm comes in place
+  (data, activeOverlaysIds, currentModelId) => {
+    const result: OverlayBioEntityRender[] = [];
+
+    activeOverlaysIds.forEach(overlayId => {
+      if (data[overlayId]?.[currentModelId]) {
+        result.push(...data[overlayId][currentModelId]);
+      }
+    });
+
+    return result;
+  },
 );
 
 export const isOverlayActiveSelector = createSelector(
   [activeOverlaysIdSelector, (_, overlayId: number): number => overlayId],
   (overlaysId, overlayId) => overlaysId.includes(overlayId),
 );
+
+export const getOverlayOrderSelector = createSelector(
+  overlaysIdsAndOrderSelector,
+  activeOverlaysIdSelector,
+  (overlaysIdsAndOrder, activeOverlaysIds) => {
+    const activeOverlaysIdsAndOrder = overlaysIdsAndOrder.filter(({ idObject }) =>
+      activeOverlaysIds.includes(idObject),
+    );
+
+    return calculateOvarlaysOrder(activeOverlaysIdsAndOrder);
+  },
+);
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts b/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts
index 21aecf10..2ba83189 100644
--- a/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts
+++ b/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts
@@ -9,6 +9,8 @@ import { parseOverlayBioEntityToOlRenderingFormat } from './overlayBioEntity.uti
 import { apiPath } from '../apiPath';
 import { modelsIdsSelector } from '../models/models.selectors';
 import type { RootState } from '../store';
+import { setMapBackground } from '../map/map.slice';
+import { emptyBackgroundIdSelector } from '../backgrounds/background.selectors';
 
 type GetOverlayBioEntityThunkProps = {
   overlayId: number;
@@ -54,3 +56,19 @@ export const getOverlayBioEntityForAllModels = createAsyncThunk<
     await Promise.all(asyncGetOverlayBioEntityFunctions);
   },
 );
+
+type GetInitOverlaysProps = { overlaysId: number[] };
+
+export const getInitOverlays = createAsyncThunk<void, GetInitOverlaysProps, { state: RootState }>(
+  'appInit/getInitOverlays',
+  async ({ overlaysId }, { dispatch, getState }): Promise<void> => {
+    const state = getState();
+
+    const emptyBackgroundId = emptyBackgroundIdSelector(state);
+    if (emptyBackgroundId) {
+      dispatch(setMapBackground(emptyBackgroundId));
+    }
+
+    overlaysId.forEach(id => dispatch(getOverlayBioEntityForAllModels({ overlayId: id })));
+  },
+);
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.utils.test.ts b/src/redux/overlayBioEntity/overlayBioEntity.utils.test.ts
new file mode 100644
index 00000000..5714a9a7
--- /dev/null
+++ b/src/redux/overlayBioEntity/overlayBioEntity.utils.test.ts
@@ -0,0 +1,64 @@
+import { calculateOvarlaysOrder } from './overlayBioEntity.utils';
+
+describe('calculateOverlaysOrder', () => {
+  const cases = [
+    {
+      data: [
+        { idObject: 1, order: 11 },
+        { idObject: 2, order: 12 },
+        { idObject: 3, order: 13 },
+      ],
+      expected: [
+        { id: 1, order: 11, calculatedOrder: 1, index: 0 },
+        { id: 2, order: 12, calculatedOrder: 2, index: 1 },
+        { id: 3, order: 13, calculatedOrder: 3, index: 2 },
+      ],
+    },
+    // different order
+    {
+      data: [
+        { idObject: 2, order: 12 },
+        { idObject: 3, order: 13 },
+        { idObject: 1, order: 11 },
+      ],
+      expected: [
+        { id: 1, order: 11, calculatedOrder: 1, index: 0 },
+        { id: 2, order: 12, calculatedOrder: 2, index: 1 },
+        { id: 3, order: 13, calculatedOrder: 3, index: 2 },
+      ],
+    },
+    {
+      data: [
+        { idObject: 1, order: 11 },
+        { idObject: 2, order: 11 },
+        { idObject: 3, order: 11 },
+      ],
+      expected: [
+        { id: 1, order: 11, calculatedOrder: 1, index: 0 },
+        { id: 2, order: 11, calculatedOrder: 2, index: 1 },
+        { id: 3, order: 11, calculatedOrder: 3, index: 2 },
+      ],
+    },
+    // different order
+    {
+      data: [
+        { idObject: 2, order: 11 },
+        { idObject: 3, order: 11 },
+        { idObject: 1, order: 11 },
+      ],
+      expected: [
+        { id: 1, order: 11, calculatedOrder: 1, index: 0 },
+        { id: 2, order: 11, calculatedOrder: 2, index: 1 },
+        { id: 3, order: 11, calculatedOrder: 3, index: 2 },
+      ],
+    },
+    {
+      data: [],
+      expected: [],
+    },
+  ];
+
+  it.each(cases)('should return valid overlays order', ({ data, expected }) => {
+    expect(calculateOvarlaysOrder(data)).toStrictEqual(expected);
+  });
+});
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.utils.ts b/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
index b875e1bb..e632f31a 100644
--- a/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
+++ b/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
@@ -1,3 +1,4 @@
+import { ONE } from '@/constants/common';
 import { OverlayBioEntityRender } from '@/types/OLrendering';
 import { OverlayBioEntity } from '@/types/models';
 
@@ -23,3 +24,45 @@ export const parseOverlayBioEntityToOlRenderingFormat = (
     }
     return acc;
   }, []);
+
+export type OverlayIdAndOrder = {
+  idObject: number;
+  order: number;
+};
+
+export type OverlayOrder = {
+  id: number;
+  order: number;
+  calculatedOrder: number;
+  index: number;
+};
+
+const byOrderOrId = (a: OverlayOrder, b: OverlayOrder): number => {
+  if (a.order === b.order) {
+    return a.id - b.id;
+  }
+  return a.order - b.order;
+};
+
+/** function calculates order of the function based on "order" property in ovarlay data. */
+export const calculateOvarlaysOrder = (
+  overlaysIdsAndOrder: OverlayIdAndOrder[],
+): OverlayOrder[] => {
+  const overlaysOrder = overlaysIdsAndOrder.map(({ idObject, order }, index) => ({
+    id: idObject,
+    order,
+    calculatedOrder: 0,
+    index,
+  }));
+
+  overlaysOrder.sort(byOrderOrId);
+
+  overlaysOrder.forEach((overlay, index) => {
+    const updatedOverlay = { ...overlay };
+    updatedOverlay.calculatedOrder = index + ONE;
+    updatedOverlay.index = index;
+    overlaysOrder[index] = updatedOverlay;
+  });
+
+  return overlaysOrder;
+};
diff --git a/src/redux/overlays/overlays.constants.ts b/src/redux/overlays/overlays.constants.ts
new file mode 100644
index 00000000..dda564cd
--- /dev/null
+++ b/src/redux/overlays/overlays.constants.ts
@@ -0,0 +1,2 @@
+/* eslint-disable no-magic-numbers */
+export const CHUNK_SIZE = 65535 * 8;
diff --git a/src/redux/overlays/overlays.mock.ts b/src/redux/overlays/overlays.mock.ts
index cdb5593c..3e1557ba 100644
--- a/src/redux/overlays/overlays.mock.ts
+++ b/src/redux/overlays/overlays.mock.ts
@@ -6,6 +6,10 @@ export const OVERLAYS_INITIAL_STATE_MOCK: OverlaysState = {
   data: [],
   loading: 'idle',
   error: DEFAULT_ERROR,
+  addOverlay: {
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
 };
 
 export const PUBLIC_OVERLAYS_MOCK: MapOverlay[] = [
@@ -77,4 +81,17 @@ export const OVERLAYS_PUBLIC_FETCHED_STATE_MOCK: OverlaysState = {
   data: PUBLIC_OVERLAYS_MOCK,
   loading: 'succeeded',
   error: DEFAULT_ERROR,
+  addOverlay: {
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
+};
+
+export const ADD_OVERLAY_MOCK = {
+  content: 'test',
+  description: 'test',
+  filename: 'unknown.txt',
+  name: 'test',
+  projectId: 'pd',
+  type: 'GENERIC',
 };
diff --git a/src/redux/overlays/overlays.reducers.test.ts b/src/redux/overlays/overlays.reducers.test.ts
index d0116134..2fe92673 100644
--- a/src/redux/overlays/overlays.reducers.test.ts
+++ b/src/redux/overlays/overlays.reducers.test.ts
@@ -1,15 +1,23 @@
+/* eslint-disable no-magic-numbers */
 import { PROJECT_ID } from '@/constants';
-import { overlaysFixture } from '@/models/fixtures/overlaysFixture';
+import {
+  createdOverlayFileFixture,
+  createdOverlayFixture,
+  overlaysFixture,
+  uploadedOverlayFileContentFixture,
+} from '@/models/fixtures/overlaysFixture';
 import {
   ToolkitStoreWithSingleSlice,
   createStoreInstanceUsingSliceReducer,
 } from '@/utils/createStoreInstanceUsingSliceReducer';
 import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
 import { HttpStatusCode } from 'axios';
+import { waitFor } from '@testing-library/react';
 import { apiPath } from '../apiPath';
 import overlaysReducer from './overlays.slice';
-import { getAllPublicOverlaysByProjectId } from './overlays.thunks';
+import { addOverlay, getAllPublicOverlaysByProjectId } from './overlays.thunks';
 import { OverlaysState } from './overlays.types';
+import { ADD_OVERLAY_MOCK } from './overlays.mock';
 
 const mockedAxiosClient = mockNetworkResponse();
 
@@ -17,6 +25,10 @@ const INITIAL_STATE: OverlaysState = {
   data: [],
   loading: 'idle',
   error: { name: '', message: '' },
+  addOverlay: {
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
 };
 
 describe('overlays reducer', () => {
@@ -30,7 +42,7 @@ describe('overlays reducer', () => {
 
     expect(overlaysReducer(undefined, action)).toEqual(INITIAL_STATE);
   });
-  it('should update store after succesfull getAllPublicOverlaysByProjectId query', async () => {
+  it('should update store after successful getAllPublicOverlaysByProjectId query', async () => {
     mockedAxiosClient
       .onGet(apiPath.getAllOverlaysByProjectIdQuery(PROJECT_ID, { publicOverlay: true }))
       .reply(HttpStatusCode.Ok, overlaysFixture);
@@ -76,4 +88,58 @@ describe('overlays reducer', () => {
       expect(promiseFulfilled).toEqual('succeeded');
     });
   });
+  it('should update store when addOverlay is pending', async () => {
+    mockedAxiosClient
+      .onPost(apiPath.createOverlayFile())
+      .reply(HttpStatusCode.Ok, createdOverlayFileFixture);
+
+    mockedAxiosClient
+      .onPost(apiPath.uploadOverlayFileContent(123))
+      .reply(HttpStatusCode.Ok, uploadedOverlayFileContentFixture);
+
+    mockedAxiosClient
+      .onPost(apiPath.createOverlay('pd'))
+      .reply(HttpStatusCode.Ok, createdOverlayFixture);
+
+    await store.dispatch(addOverlay(ADD_OVERLAY_MOCK));
+    const { loading } = store.getState().overlays.addOverlay;
+
+    waitFor(() => {
+      expect(loading).toEqual('pending');
+    });
+  });
+
+  it('should update store after successful addOverlay', async () => {
+    mockedAxiosClient
+      .onPost(apiPath.createOverlayFile())
+      .reply(HttpStatusCode.Ok, createdOverlayFileFixture);
+
+    mockedAxiosClient
+      .onPost(apiPath.uploadOverlayFileContent(123))
+      .reply(HttpStatusCode.Ok, uploadedOverlayFileContentFixture);
+
+    mockedAxiosClient
+      .onPost(apiPath.createOverlay('pd'))
+      .reply(HttpStatusCode.Ok, createdOverlayFixture);
+
+    await store.dispatch(addOverlay(ADD_OVERLAY_MOCK));
+    const { loading, error } = store.getState().overlays.addOverlay;
+
+    expect(loading).toEqual('succeeded');
+    expect(error).toEqual({ message: '', name: '' });
+  });
+  it('should update store after failed addOverlay', async () => {
+    mockedAxiosClient.onPost(apiPath.createOverlayFile()).reply(HttpStatusCode.NotFound, undefined);
+
+    mockedAxiosClient
+      .onPost(apiPath.uploadOverlayFileContent(123))
+      .reply(HttpStatusCode.NotFound, undefined);
+
+    mockedAxiosClient.onPost(apiPath.createOverlay('pd')).reply(HttpStatusCode.NotFound, undefined);
+
+    await store.dispatch(addOverlay(ADD_OVERLAY_MOCK));
+    const { loading } = store.getState().overlays.addOverlay;
+
+    expect(loading).toEqual('failed');
+  });
 });
diff --git a/src/redux/overlays/overlays.reducers.ts b/src/redux/overlays/overlays.reducers.ts
index 99e493ea..d8f12eef 100644
--- a/src/redux/overlays/overlays.reducers.ts
+++ b/src/redux/overlays/overlays.reducers.ts
@@ -1,5 +1,5 @@
 import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
-import { getAllPublicOverlaysByProjectId } from './overlays.thunks';
+import { addOverlay, getAllPublicOverlaysByProjectId } from './overlays.thunks';
 import { OverlaysState } from './overlays.types';
 
 export const getAllPublicOverlaysByProjectIdReducer = (
@@ -17,3 +17,16 @@ export const getAllPublicOverlaysByProjectIdReducer = (
     // TODO to discuss manage state of failure
   });
 };
+
+export const addOverlayReducer = (builder: ActionReducerMapBuilder<OverlaysState>): void => {
+  builder.addCase(addOverlay.pending, state => {
+    state.addOverlay.loading = 'pending';
+  });
+  builder.addCase(addOverlay.fulfilled, state => {
+    state.addOverlay.loading = 'succeeded';
+  });
+  builder.addCase(addOverlay.rejected, state => {
+    state.addOverlay.loading = 'failed';
+    // TODO to discuss manage state of failure
+  });
+};
diff --git a/src/redux/overlays/overlays.selectors.ts b/src/redux/overlays/overlays.selectors.ts
index f9d36cad..03ee76e6 100644
--- a/src/redux/overlays/overlays.selectors.ts
+++ b/src/redux/overlays/overlays.selectors.ts
@@ -7,3 +7,12 @@ export const overlaysDataSelector = createSelector(
   overlaysSelector,
   overlays => overlays?.data || [],
 );
+
+export const overlaysIdsAndOrderSelector = createSelector(overlaysDataSelector, overlays =>
+  overlays.map(({ idObject, order }) => ({ idObject, order })),
+);
+
+export const loadingAddOverlay = createSelector(
+  overlaysSelector,
+  state => state.addOverlay.loading,
+);
diff --git a/src/redux/overlays/overlays.slice.ts b/src/redux/overlays/overlays.slice.ts
index 8d259288..5f49156a 100644
--- a/src/redux/overlays/overlays.slice.ts
+++ b/src/redux/overlays/overlays.slice.ts
@@ -1,11 +1,15 @@
 import { createSlice } from '@reduxjs/toolkit';
-import { getAllPublicOverlaysByProjectIdReducer } from './overlays.reducers';
+import { addOverlayReducer, getAllPublicOverlaysByProjectIdReducer } from './overlays.reducers';
 import { OverlaysState } from './overlays.types';
 
 const initialState: OverlaysState = {
   data: [],
   loading: 'idle',
   error: { name: '', message: '' },
+  addOverlay: {
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
 };
 
 const overlaysState = createSlice({
@@ -14,6 +18,7 @@ const overlaysState = createSlice({
   reducers: {},
   extraReducers: builder => {
     getAllPublicOverlaysByProjectIdReducer(builder);
+    addOverlayReducer(builder);
   },
 });
 
diff --git a/src/redux/overlays/overlays.thunks.ts b/src/redux/overlays/overlays.thunks.ts
index 6a019333..330e5ee9 100644
--- a/src/redux/overlays/overlays.thunks.ts
+++ b/src/redux/overlays/overlays.thunks.ts
@@ -1,10 +1,17 @@
-import { mapOverlay } from '@/models/mapOverlay';
+/* eslint-disable no-magic-numbers */
+import {
+  createdOverlayFileSchema,
+  createdOverlaySchema,
+  mapOverlay,
+  uploadedOverlayFileContentSchema,
+} from '@/models/mapOverlay';
 import { axiosInstance } from '@/services/api/utils/axiosInstance';
-import { MapOverlay } from '@/types/models';
+import { CreatedOverlay, CreatedOverlayFile, MapOverlay } from '@/types/models';
 import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
 import { createAsyncThunk } from '@reduxjs/toolkit';
 import { z } from 'zod';
 import { apiPath } from '../apiPath';
+import { CHUNK_SIZE } from './overlays.constants';
 
 export const getAllPublicOverlaysByProjectId = createAsyncThunk(
   'overlays/getAllPublicOverlaysByProjectId',
@@ -18,3 +25,136 @@ export const getAllPublicOverlaysByProjectId = createAsyncThunk(
     return isDataValid ? response.data : [];
   },
 );
+
+/** UTILS */
+
+type CreateFileArgs = {
+  filename: string;
+  content: string;
+};
+
+const createFile = async ({ filename, content }: CreateFileArgs): Promise<CreatedOverlayFile> => {
+  const fileParams = {
+    filename: `C:\\fakepath\\${filename}`,
+    length: content.length.toString(),
+  };
+
+  const response = await axiosInstance.post(
+    apiPath.createOverlayFile(),
+    new URLSearchParams(fileParams),
+    {
+      withCredentials: true,
+    },
+  );
+
+  const isDataValid = validateDataUsingZodSchema(response.data, createdOverlayFileSchema);
+  return isDataValid ? response.data : undefined;
+};
+
+type UploadContentArgs = {
+  createdFile: CreatedOverlayFile;
+  overlayContent: string;
+};
+const uploadContent = async ({ createdFile, overlayContent }: UploadContentArgs): Promise<void> => {
+  const data = new Uint8Array(new TextEncoder().encode(overlayContent));
+  let uploadedLength = 0;
+
+  const sendChunk = async (): Promise<void> => {
+    if (uploadedLength >= data.length) {
+      return;
+    }
+
+    const chunk = data.slice(uploadedLength, uploadedLength + CHUNK_SIZE);
+
+    const responeJSON = await fetch(
+      `${process.env.NEXT_PUBLIC_BASE_API_URL}/${apiPath.uploadOverlayFileContent(createdFile.id)}`,
+      {
+        method: 'POST',
+        credentials: 'include',
+        body: chunk,
+      },
+    );
+
+    const response = await responeJSON.json();
+    validateDataUsingZodSchema(response, uploadedOverlayFileContentSchema);
+
+    uploadedLength += chunk.length;
+    sendChunk();
+  };
+
+  await sendChunk();
+};
+
+type CreatedOverlayArgs = {
+  createdFile: CreatedOverlayFile;
+  description: string;
+  name: string;
+  type: string;
+  projectId: string;
+};
+
+const creteOverlay = async ({
+  createdFile,
+  description,
+  type,
+  name,
+  projectId,
+}: CreatedOverlayArgs): Promise<CreatedOverlay> => {
+  const data = {
+    name,
+    description,
+    filename: createdFile.filename,
+    googleLicenseConsent: false.toString(),
+    type,
+    fileId: createdFile.id.toString(),
+  };
+
+  const overlay = new URLSearchParams(data);
+
+  const response = await axiosInstance.post(apiPath.createOverlay(projectId), overlay, {
+    withCredentials: true,
+  });
+
+  const isDataValid = validateDataUsingZodSchema(response.data, createdOverlaySchema);
+
+  return isDataValid ? response.data : undefined;
+};
+
+type AddOverlayArgs = {
+  filename: string;
+  content: string;
+  description: string;
+  type: string;
+  name: string;
+  projectId: string;
+};
+
+export const addOverlay = createAsyncThunk(
+  'overlays/addOverlay',
+  async ({
+    filename,
+    content,
+    description,
+    name,
+    type,
+    projectId,
+  }: AddOverlayArgs): Promise<void> => {
+    const createdFile = await createFile({
+      filename,
+      content,
+    });
+
+    await uploadContent({
+      createdFile,
+      overlayContent: content,
+    });
+
+    await creteOverlay({
+      createdFile,
+      description,
+      name,
+      type,
+      projectId,
+    });
+  },
+);
diff --git a/src/redux/overlays/overlays.types.ts b/src/redux/overlays/overlays.types.ts
index ee00e945..15d4d813 100644
--- a/src/redux/overlays/overlays.types.ts
+++ b/src/redux/overlays/overlays.types.ts
@@ -1,4 +1,12 @@
 import { FetchDataState } from '@/types/fetchDataState';
+import { Loading } from '@/types/loadingState';
 import { MapOverlay } from '@/types/models';
 
-export type OverlaysState = FetchDataState<MapOverlay[] | []>;
+export type AddOverlayState = {
+  addOverlay: {
+    loading: Loading;
+    error: Error;
+  };
+};
+
+export type OverlaysState = FetchDataState<MapOverlay[] | []> & AddOverlayState;
diff --git a/src/redux/project/project.selectors.ts b/src/redux/project/project.selectors.ts
index 610a6cce..c5ac3403 100644
--- a/src/redux/project/project.selectors.ts
+++ b/src/redux/project/project.selectors.ts
@@ -31,3 +31,8 @@ export const projectDirectorySelector = createSelector(
   projectDataSelector,
   projectData => projectData?.directory,
 );
+
+export const projectIdSelector = createSelector(
+  projectDataSelector,
+  projectData => projectData?.projectId,
+);
diff --git a/src/redux/root/init.thunks.ts b/src/redux/root/init.thunks.ts
index 4591391b..c4ac1927 100644
--- a/src/redux/root/init.thunks.ts
+++ b/src/redux/root/init.thunks.ts
@@ -17,7 +17,9 @@ import {
 import { getSearchData } from '../search/search.thunks';
 import { setPerfectMatch } from '../search/search.slice';
 import { getSessionValid } from '../user/user.thunks';
-import { getConfigurationOptions } from '../configuration/configuration.thunks';
+import { getInitOverlays } from '../overlayBioEntity/overlayBioEntity.thunk';
+import { getConfiguration, getConfigurationOptions } from '../configuration/configuration.thunks';
+import { getStatisticsById } from '../statistics/statistics.thunks';
 
 interface InitializeAppParams {
   queryData: QueryData;
@@ -28,7 +30,7 @@ export const fetchInitialAppData = createAsyncThunk<
   InitializeAppParams,
   { dispatch: AppDispatch }
 >('appInit/fetchInitialAppData', async ({ queryData }, { dispatch }): Promise<void> => {
-  /** Fetch all data required for renderin map */
+  /** Fetch all data required for rendering map */
   await Promise.all([
     dispatch(getConfigurationOptions()),
     dispatch(getProjectById(PROJECT_ID)),
@@ -48,6 +50,10 @@ export const fetchInitialAppData = createAsyncThunk<
   // Check if auth token is valid
   dispatch(getSessionValid());
 
+  // Fetch data needed for export
+  dispatch(getStatisticsById(PROJECT_ID));
+  dispatch(getConfiguration());
+
   /** Trigger search */
   if (queryData.searchValue) {
     dispatch(setPerfectMatch(queryData.perfectMatch));
@@ -59,4 +65,9 @@ export const fetchInitialAppData = createAsyncThunk<
     );
     dispatch(openSearchDrawerWithSelectedTab(getDefaultSearchTab(queryData.searchValue)));
   }
+
+  /** fetch overlays  */
+  if (queryData.overlaysId) {
+    dispatch(getInitOverlays({ overlaysId: queryData.overlaysId }));
+  }
 });
diff --git a/src/redux/root/query.selectors.ts b/src/redux/root/query.selectors.ts
index 55929fca..98660410 100644
--- a/src/redux/root/query.selectors.ts
+++ b/src/redux/root/query.selectors.ts
@@ -1,17 +1,33 @@
 import { QueryDataParams } from '@/types/query';
 import { createSelector } from '@reduxjs/toolkit';
+import { ZERO } from '@/constants/common';
 import { mapDataSelector } from '../map/map.selectors';
 import { perfectMatchSelector, searchValueSelector } from '../search/search.selectors';
+import { activeOverlaysIdSelector } from '../overlayBioEntity/overlayBioEntity.selector';
 
 export const queryDataParamsSelector = createSelector(
   searchValueSelector,
   perfectMatchSelector,
   mapDataSelector,
-  (searchValue, perfectMatch, { modelId, backgroundId, position }): QueryDataParams => ({
-    searchValue: searchValue.join(';'),
+  activeOverlaysIdSelector,
+  (
+    searchValue,
     perfectMatch,
-    modelId,
-    backgroundId,
-    ...position.last,
-  }),
+    { modelId, backgroundId, position },
+    activeOverlaysId,
+  ): QueryDataParams => {
+    const queryDataParams: QueryDataParams = {
+      searchValue: searchValue.join(';'),
+      perfectMatch,
+      modelId,
+      backgroundId,
+      ...position.last,
+    };
+
+    if (activeOverlaysId.length > ZERO) {
+      queryDataParams.overlaysId = activeOverlaysId.join(',');
+    }
+
+    return queryDataParams;
+  },
 );
diff --git a/src/redux/root/root.fixtures.ts b/src/redux/root/root.fixtures.ts
index 966bb1d5..ba66c5ef 100644
--- a/src/redux/root/root.fixtures.ts
+++ b/src/redux/root/root.fixtures.ts
@@ -17,6 +17,7 @@ import { REACTIONS_STATE_INITIAL_MOCK } from '../reactions/reactions.mock';
 import { SEARCH_STATE_INITIAL_MOCK } from '../search/search.mock';
 import { RootState } from '../store';
 import { USER_INITIAL_STATE_MOCK } from '../user/user.mock';
+import { STATISTICS_STATE_INITIAL_MOCK } from '../statistics/statistics.mock';
 
 export const INITIAL_STORE_STATE_MOCK: RootState = {
   search: SEARCH_STATE_INITIAL_MOCK,
@@ -37,4 +38,5 @@ export const INITIAL_STORE_STATE_MOCK: RootState = {
   cookieBanner: COOKIE_BANNER_INITIAL_STATE_MOCK,
   user: USER_INITIAL_STATE_MOCK,
   legend: LEGEND_INITIAL_STATE_MOCK,
+  statistics: STATISTICS_STATE_INITIAL_MOCK,
 };
diff --git a/src/redux/statistics/statistics.mock.ts b/src/redux/statistics/statistics.mock.ts
new file mode 100644
index 00000000..9c753dcd
--- /dev/null
+++ b/src/redux/statistics/statistics.mock.ts
@@ -0,0 +1,8 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { StatisticsState } from './statistics.types';
+
+export const STATISTICS_STATE_INITIAL_MOCK: StatisticsState = {
+  data: undefined,
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
diff --git a/src/redux/statistics/statistics.reducers.test.ts b/src/redux/statistics/statistics.reducers.test.ts
new file mode 100644
index 00000000..af16b53b
--- /dev/null
+++ b/src/redux/statistics/statistics.reducers.test.ts
@@ -0,0 +1,70 @@
+import { PROJECT_ID } from '@/constants';
+import {
+  ToolkitStoreWithSingleSlice,
+  createStoreInstanceUsingSliceReducer,
+} from '@/utils/createStoreInstanceUsingSliceReducer';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { HttpStatusCode } from 'axios';
+import { waitFor } from '@testing-library/react';
+import { statisticsFixture } from '@/models/fixtures/statisticsFixture';
+import { StatisticsState } from './statistics.types';
+import statisticsReducer from './statistics.slice';
+import { apiPath } from '../apiPath';
+import { getStatisticsById } from './statistics.thunks';
+
+const mockedAxiosClient = mockNetworkResponse();
+
+const INITIAL_STATE: StatisticsState = {
+  data: undefined,
+  loading: 'idle',
+  error: { name: '', message: '' },
+};
+
+describe('statistics reducer', () => {
+  let store = {} as ToolkitStoreWithSingleSlice<StatisticsState>;
+  beforeEach(() => {
+    store = createStoreInstanceUsingSliceReducer('statistics', statisticsReducer);
+  });
+
+  it('should match initial state', () => {
+    const action = { type: 'unknown' };
+
+    expect(statisticsReducer(undefined, action)).toEqual(INITIAL_STATE);
+  });
+
+  it('should update store after successful getStatisticById query', async () => {
+    mockedAxiosClient
+      .onGet(apiPath.getStatisticsById(PROJECT_ID))
+      .reply(HttpStatusCode.Ok, statisticsFixture);
+
+    const { type } = await store.dispatch(getStatisticsById(PROJECT_ID));
+    const { data, loading, error } = store.getState().statistics;
+
+    expect(type).toBe('statistics/getStatisticsById/fulfilled');
+
+    waitFor(() => {
+      expect(loading).toEqual('pending');
+    });
+
+    expect(loading).toEqual('succeeded');
+    expect(error).toEqual({ message: '', name: '' });
+    expect(data).toEqual(statisticsFixture);
+  });
+
+  it('should update store after failed getStatisticById query', async () => {
+    mockedAxiosClient
+      .onGet(apiPath.getStatisticsById(PROJECT_ID))
+      .reply(HttpStatusCode.NotFound, undefined);
+
+    const { type } = await store.dispatch(getStatisticsById(PROJECT_ID));
+    const { loading } = store.getState().statistics;
+
+    expect(type).toBe('statistics/getStatisticsById/rejected');
+
+    waitFor(() => {
+      expect(loading).toEqual('pending');
+    });
+
+    expect(loading).toEqual('failed');
+  });
+});
diff --git a/src/redux/statistics/statistics.reducers.ts b/src/redux/statistics/statistics.reducers.ts
new file mode 100644
index 00000000..0829625f
--- /dev/null
+++ b/src/redux/statistics/statistics.reducers.ts
@@ -0,0 +1,18 @@
+import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
+import { StatisticsState } from './statistics.types';
+import { getStatisticsById } from './statistics.thunks';
+
+export const getStatisticsByIdReducer = (
+  builder: ActionReducerMapBuilder<StatisticsState>,
+): void => {
+  builder.addCase(getStatisticsById.pending, state => {
+    state.loading = 'pending';
+  });
+  builder.addCase(getStatisticsById.fulfilled, (state, action) => {
+    state.data = action.payload;
+    state.loading = 'succeeded';
+  });
+  builder.addCase(getStatisticsById.rejected, state => {
+    state.loading = 'failed';
+  });
+};
diff --git a/src/redux/statistics/statistics.selectors.ts b/src/redux/statistics/statistics.selectors.ts
new file mode 100644
index 00000000..e0bb3259
--- /dev/null
+++ b/src/redux/statistics/statistics.selectors.ts
@@ -0,0 +1,16 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { rootSelector } from '../root/root.selectors';
+
+export const statisticsSelector = createSelector(rootSelector, state => state.statistics);
+
+export const loadingStatisticsSelector = createSelector(statisticsSelector, state => state.loading);
+
+export const statisticsDataSelector = createSelector(
+  statisticsSelector,
+  statistics => statistics?.data,
+);
+
+export const elementAnnotationsSelector = createSelector(
+  statisticsDataSelector,
+  statistics => statistics?.elementAnnotations,
+);
diff --git a/src/redux/statistics/statistics.slice.ts b/src/redux/statistics/statistics.slice.ts
new file mode 100644
index 00000000..f2cf9f80
--- /dev/null
+++ b/src/redux/statistics/statistics.slice.ts
@@ -0,0 +1,20 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { StatisticsState } from './statistics.types';
+import { getStatisticsByIdReducer } from './statistics.reducers';
+
+const initialState: StatisticsState = {
+  data: undefined,
+  loading: 'idle',
+  error: { name: '', message: '' },
+};
+
+export const statisticsSlice = createSlice({
+  name: 'statistics',
+  initialState,
+  reducers: {},
+  extraReducers: builder => {
+    getStatisticsByIdReducer(builder);
+  },
+});
+
+export default statisticsSlice.reducer;
diff --git a/src/redux/statistics/statistics.thunks.ts b/src/redux/statistics/statistics.thunks.ts
new file mode 100644
index 00000000..df5b6589
--- /dev/null
+++ b/src/redux/statistics/statistics.thunks.ts
@@ -0,0 +1,17 @@
+import { axiosInstance } from '@/services/api/utils/axiosInstance';
+import { Statistics } from '@/types/models';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { statisticsSchema } from '@/models/statisticsSchema';
+import { apiPath } from '../apiPath';
+
+export const getStatisticsById = createAsyncThunk(
+  'statistics/getStatisticsById',
+  async (id: string): Promise<Statistics | undefined> => {
+    const response = await axiosInstance.get<Statistics>(apiPath.getStatisticsById(id));
+
+    const isDataValid = validateDataUsingZodSchema(response.data, statisticsSchema);
+
+    return isDataValid ? response.data : undefined;
+  },
+);
diff --git a/src/redux/statistics/statistics.types.ts b/src/redux/statistics/statistics.types.ts
new file mode 100644
index 00000000..077d4df1
--- /dev/null
+++ b/src/redux/statistics/statistics.types.ts
@@ -0,0 +1,4 @@
+import { FetchDataState } from '@/types/fetchDataState';
+import { Statistics } from '@/types/models';
+
+export type StatisticsState = FetchDataState<Statistics>;
diff --git a/src/redux/store.ts b/src/redux/store.ts
index 663bc180..b79cf2b2 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -24,6 +24,7 @@ import {
 } from '@reduxjs/toolkit';
 import legendReducer from './legend/legend.slice';
 import { mapListenerMiddleware } from './map/middleware/map.middleware';
+import statisticsReducer from './statistics/statistics.slice';
 
 export const reducers = {
   search: searchReducer,
@@ -44,6 +45,7 @@ export const reducers = {
   configuration: configurationReducer,
   overlayBioEntity: overlayBioEntityReducer,
   legend: legendReducer,
+  statistics: statisticsReducer,
 };
 
 export const middlewares = [mapListenerMiddleware.middleware];
diff --git a/src/shared/Input/Input.component.test.tsx b/src/shared/Input/Input.component.test.tsx
new file mode 100644
index 00000000..a26f46fc
--- /dev/null
+++ b/src/shared/Input/Input.component.test.tsx
@@ -0,0 +1,70 @@
+/* eslint-disable no-magic-numbers */
+import React from 'react';
+import { render, fireEvent, screen } from '@testing-library/react';
+import { Input } from './Input.component';
+
+describe('Input - component', () => {
+  it('should render with proper testid', () => {
+    render(<Input data-testid="input" />);
+    const inputElement = screen.getByTestId('input');
+    expect(inputElement).toBeInTheDocument();
+  });
+
+  it('should apply the default style and size variants when none are provided', () => {
+    render(<Input data-testid="input" />);
+    const inputElement = screen.getByTestId('input');
+    expect(inputElement).toHaveClass('bg-cultured');
+    expect(inputElement).toHaveClass('rounded-s');
+  });
+
+  it('should apply the specified style variant', () => {
+    render(<Input styleVariant="primary" data-testid="input" />);
+    const inputElement = screen.getByTestId('input');
+    expect(inputElement).toHaveClass('bg-cultured');
+  });
+
+  it('should apply the specified size variant', () => {
+    render(<Input sizeVariant="medium" data-testid="input" />);
+    const inputElement = screen.getByTestId('input');
+    expect(inputElement).toHaveClass('rounded-lg');
+    expect(inputElement).toHaveClass('h-12');
+    expect(inputElement).toHaveClass('text-sm');
+  });
+
+  it('should merge custom class with style and size variant classes', () => {
+    render(
+      <Input
+        className="text-red-500"
+        styleVariant="primary"
+        sizeVariant="medium"
+        data-testid="input"
+      />,
+    );
+    const inputElement = screen.getByTestId('input');
+    expect(inputElement).toHaveClass('text-red-500');
+    expect(inputElement).toHaveClass('h-12');
+    expect(inputElement).toHaveClass('bg-cultured');
+  });
+
+  it(' should handle onChange event', () => {
+    const handleChange = jest.fn();
+    render(<Input onChange={handleChange} data-testid="input" />);
+    const inputElement = screen.getByTestId('input');
+    fireEvent.change(inputElement, { target: { value: 'Hello, World!' } });
+    expect(handleChange).toHaveBeenCalledTimes(1);
+  });
+
+  it('should render with a placeholder', () => {
+    const placeholderText = 'Type here...';
+    render(<Input placeholder={placeholderText} data-testid="input" />);
+    const inputElement = screen.getByTestId('input');
+    expect(inputElement).toHaveAttribute('placeholder', placeholderText);
+  });
+
+  it('should render with a default value', () => {
+    const defaultValue = 'Initial value';
+    render(<Input defaultValue={defaultValue} data-testid="input" />);
+    const inputElement = screen.getByTestId('input');
+    expect(inputElement).toHaveValue(defaultValue);
+  });
+});
diff --git a/src/shared/Input/Input.component.tsx b/src/shared/Input/Input.component.tsx
new file mode 100644
index 00000000..68cf9097
--- /dev/null
+++ b/src/shared/Input/Input.component.tsx
@@ -0,0 +1,33 @@
+import React, { InputHTMLAttributes } from 'react';
+import { twMerge } from 'tailwind-merge';
+
+type StyleVariant = 'primary';
+type SizeVariant = 'small' | 'medium';
+
+type InputProps = {
+  className?: string;
+  styleVariant?: StyleVariant;
+  sizeVariant?: SizeVariant;
+} & InputHTMLAttributes<HTMLInputElement>;
+
+const styleVariants = {
+  primary:
+    'w-full border border-transparent bg-cultured px-2 py-2.5 font-semibold outline-none hover:border-greyscale-600 focus:border-greyscale-600',
+} as const;
+
+const sizeVariants = {
+  small: 'rounded-s h-10 text-xs',
+  medium: 'rounded-lg h-12 text-sm',
+} as const;
+
+export const Input = ({
+  className = '',
+  sizeVariant = 'small',
+  styleVariant = 'primary',
+  ...props
+}: InputProps): React.ReactNode => (
+  <input
+    {...props}
+    className={twMerge(styleVariants[styleVariant], sizeVariants[sizeVariant], className)}
+  />
+);
diff --git a/src/shared/Input/index.ts b/src/shared/Input/index.ts
new file mode 100644
index 00000000..dfcccdc6
--- /dev/null
+++ b/src/shared/Input/index.ts
@@ -0,0 +1 @@
+export { Input } from './Input.component';
diff --git a/src/shared/Textarea/Textarea.component.test.tsx b/src/shared/Textarea/Textarea.component.test.tsx
new file mode 100644
index 00000000..e337f637
--- /dev/null
+++ b/src/shared/Textarea/Textarea.component.test.tsx
@@ -0,0 +1,53 @@
+/* eslint-disable no-magic-numbers */
+import React from 'react';
+import { render, fireEvent, screen } from '@testing-library/react';
+import { Textarea } from './Textarea.component';
+
+describe('Textarea - Component', () => {
+  it('should render with proper testid', () => {
+    render(<Textarea data-testid="textarea" />);
+    const textareaElement = screen.getByTestId('textarea');
+    expect(textareaElement).toBeInTheDocument();
+  });
+
+  it('should apply the default style variant when none is provided', () => {
+    render(<Textarea data-testid="textarea" />);
+    const textareaElement = screen.getByTestId('textarea');
+    expect(textareaElement).toHaveClass('bg-cultured');
+  });
+
+  it('should apply the specified style variant', () => {
+    render(<Textarea styleVariant="primary" data-testid="textarea" />);
+    const textareaElement = screen.getByTestId('textarea');
+    expect(textareaElement).toHaveClass('bg-cultured');
+  });
+
+  it('should merge custom class with style variant classes', () => {
+    render(<Textarea className="text-red-500" styleVariant="primary" data-testid="textarea" />);
+    const textareaElement = screen.getByTestId('textarea');
+    expect(textareaElement).toHaveClass('text-red-500');
+    expect(textareaElement).toHaveClass('bg-cultured');
+  });
+
+  it('should handle onChange event', () => {
+    const handleChange = jest.fn();
+    render(<Textarea onChange={handleChange} data-testid="textarea" />);
+    const textareaElement = screen.getByTestId('textarea');
+    fireEvent.change(textareaElement, { target: { value: 'Hello, World!' } });
+    expect(handleChange).toHaveBeenCalledTimes(1);
+  });
+
+  it('should render with a placeholder', () => {
+    const placeholderText = 'Type here...';
+    render(<Textarea placeholder={placeholderText} data-testid="textarea" />);
+    const textareaElement = screen.getByTestId('textarea');
+    expect(textareaElement).toHaveAttribute('placeholder', placeholderText);
+  });
+
+  it('should render with a default value', () => {
+    const defaultValue = 'Initial value';
+    render(<Textarea defaultValue={defaultValue} data-testid="textarea" />);
+    const textareaElement = screen.getByTestId('textarea');
+    expect(textareaElement).toHaveValue(defaultValue);
+  });
+});
diff --git a/src/shared/Textarea/Textarea.component.tsx b/src/shared/Textarea/Textarea.component.tsx
new file mode 100644
index 00000000..b300f21a
--- /dev/null
+++ b/src/shared/Textarea/Textarea.component.tsx
@@ -0,0 +1,22 @@
+import React, { TextareaHTMLAttributes } from 'react';
+import { twMerge } from 'tailwind-merge';
+
+type StyleVariant = 'primary';
+
+type TextareaProps = {
+  className?: string;
+  styleVariant?: StyleVariant;
+} & TextareaHTMLAttributes<HTMLTextAreaElement>;
+
+const styleVariants = {
+  primary:
+    'w-full resize-none rounded-lg border border-transparent bg-cultured px-2 py-2.5 text-xs font-semibold outline-none  hover:border-greyscale-600 focus:border-greyscale-600',
+} as const;
+
+export const Textarea = ({
+  className = '',
+  styleVariant = 'primary',
+  ...props
+}: TextareaProps): React.ReactNode => (
+  <textarea {...props} className={twMerge(styleVariants[styleVariant], className)} />
+);
diff --git a/src/shared/Textarea/index.ts b/src/shared/Textarea/index.ts
new file mode 100644
index 00000000..11d2fe00
--- /dev/null
+++ b/src/shared/Textarea/index.ts
@@ -0,0 +1 @@
+export { Textarea } from './Textarea.component';
diff --git a/src/types/OLrendering.ts b/src/types/OLrendering.ts
index 3a651659..11ab030c 100644
--- a/src/types/OLrendering.ts
+++ b/src/types/OLrendering.ts
@@ -3,9 +3,13 @@ import { Color } from './models';
 export type OverlayBioEntityRender = {
   id: number;
   modelId: number;
+  /** bottom left corner of whole element, Xmin */
   x1: number;
+  /** bottom left corner of whole element, Ymin */
   y1: number;
+  /** top righ corner of whole element, xMax */
   x2: number;
+  /** top righ corner of whole element, yMax */
   y2: number;
   width: number;
   height: number;
diff --git a/src/types/models.ts b/src/types/models.ts
index a1e01c3d..8f4582e5 100644
--- a/src/types/models.ts
+++ b/src/types/models.ts
@@ -4,12 +4,18 @@ import { bioEntitySchema } from '@/models/bioEntitySchema';
 import { chemicalSchema } from '@/models/chemicalSchema';
 import { colorSchema } from '@/models/colorSchema';
 import { configurationOptionSchema } from '@/models/configurationOptionSchema';
+import { configurationSchema } from '@/models/configurationSchema';
 import { disease } from '@/models/disease';
 import { drugSchema } from '@/models/drugSchema';
 import { elementSearchResult, elementSearchResultType } from '@/models/elementSearchResult';
 import { loginSchema } from '@/models/loginSchema';
 import { mapBackground } from '@/models/mapBackground';
-import { mapOverlay } from '@/models/mapOverlay';
+import {
+  createdOverlayFileSchema,
+  createdOverlaySchema,
+  mapOverlay,
+  uploadedOverlayFileContentSchema,
+} from '@/models/mapOverlay';
 import { mapModelSchema } from '@/models/modelSchema';
 import { organism } from '@/models/organism';
 import { overlayBioEntitySchema } from '@/models/overlayBioEntitySchema';
@@ -24,6 +30,7 @@ import { reactionSchema } from '@/models/reaction';
 import { reactionLineSchema } from '@/models/reactionLineSchema';
 import { referenceSchema } from '@/models/referenceSchema';
 import { sessionSchemaValid } from '@/models/sessionValidSchema';
+import { statisticsSchema } from '@/models/statisticsSchema';
 import { targetSchema } from '@/models/targetSchema';
 import { z } from 'zod';
 
@@ -51,5 +58,10 @@ export type ElementSearchResultType = z.infer<typeof elementSearchResultType>;
 export type SessionValid = z.infer<typeof sessionSchemaValid>;
 export type Login = z.infer<typeof loginSchema>;
 export type ConfigurationOption = z.infer<typeof configurationOptionSchema>;
+export type Configuration = z.infer<typeof configurationSchema>;
 export type OverlayBioEntity = z.infer<typeof overlayBioEntitySchema>;
+export type CreatedOverlayFile = z.infer<typeof createdOverlayFileSchema>;
+export type UploadedOverlayFileContent = z.infer<typeof uploadedOverlayFileContentSchema>;
+export type CreatedOverlay = z.infer<typeof createdOverlaySchema>;
 export type Color = z.infer<typeof colorSchema>;
+export type Statistics = z.infer<typeof statisticsSchema>;
diff --git a/src/types/query.ts b/src/types/query.ts
index a6696aa9..98309123 100644
--- a/src/types/query.ts
+++ b/src/types/query.ts
@@ -6,6 +6,7 @@ export interface QueryData {
   modelId?: number;
   backgroundId?: number;
   initialPosition?: Partial<Point>;
+  overlaysId?: number[];
 }
 
 export interface QueryDataParams {
@@ -16,6 +17,7 @@ export interface QueryDataParams {
   x?: number;
   y?: number;
   z?: number;
+  overlaysId?: string;
 }
 
 export interface QueryDataRouterParams {
@@ -26,4 +28,5 @@ export interface QueryDataRouterParams {
   x?: string;
   y?: string;
   z?: string;
+  overlaysId?: string;
 }
diff --git a/src/utils/number/roundToTwoDigits.test.ts b/src/utils/number/roundToTwoDigits.test.ts
new file mode 100644
index 00000000..68fa6ecf
--- /dev/null
+++ b/src/utils/number/roundToTwoDigits.test.ts
@@ -0,0 +1,32 @@
+/* eslint-disable no-magic-numbers */
+import { roundToTwoDigits } from './roundToTwoDigits';
+
+describe('roundToTwoDiggits', () => {
+  it('should round a positive number with more than two decimal places to two decimal places', () => {
+    expect(roundToTwoDigits(3.14159265359)).toBe(3.14);
+    expect(roundToTwoDigits(2.71828182845)).toBe(2.72);
+    expect(roundToTwoDigits(1.23456789)).toBe(1.23);
+  });
+
+  it('should round a negative number with more than two decimal places to two decimal places', () => {
+    expect(roundToTwoDigits(-3.14159265359)).toBe(-3.14);
+    expect(roundToTwoDigits(-2.71828182845)).toBe(-2.72);
+    expect(roundToTwoDigits(-1.23456789)).toBe(-1.23);
+  });
+
+  it('should round a number with exactly two decimal places to two decimal places', () => {
+    expect(roundToTwoDigits(3.14)).toBe(3.14);
+    expect(roundToTwoDigits(2.72)).toBe(2.72);
+    expect(roundToTwoDigits(1.23)).toBe(1.23);
+  });
+
+  it('should round a number with less than two decimal places to two decimal places', () => {
+    expect(roundToTwoDigits(3)).toBe(3.0);
+    expect(roundToTwoDigits(2.7)).toBe(2.7);
+    expect(roundToTwoDigits(1.2)).toBe(1.2);
+  });
+
+  it('should round zero to two decimal places', () => {
+    expect(roundToTwoDigits(0)).toBe(0);
+  });
+});
diff --git a/src/utils/number/roundToTwoDigits.ts b/src/utils/number/roundToTwoDigits.ts
new file mode 100644
index 00000000..0a3aa52d
--- /dev/null
+++ b/src/utils/number/roundToTwoDigits.ts
@@ -0,0 +1,2 @@
+const TWO_DIGITS = 100;
+export const roundToTwoDigits = (x: number): number => Math.round(x * TWO_DIGITS) / TWO_DIGITS;
diff --git a/src/utils/parseQueryToTypes.test.ts b/src/utils/parseQueryToTypes.test.ts
index 83d99107..113111d7 100644
--- a/src/utils/parseQueryToTypes.test.ts
+++ b/src/utils/parseQueryToTypes.test.ts
@@ -10,6 +10,7 @@ describe('parseQueryToTypes', () => {
       modelId: undefined,
       backgroundId: undefined,
       initialPosition: { x: undefined, y: undefined, z: undefined },
+      overlaysId: undefined,
     });
 
     expect(parseQueryToTypes({ perfectMatch: 'true' })).toEqual({
@@ -18,6 +19,7 @@ describe('parseQueryToTypes', () => {
       modelId: undefined,
       backgroundId: undefined,
       initialPosition: { x: undefined, y: undefined, z: undefined },
+      overlaysId: undefined,
     });
 
     expect(parseQueryToTypes({ perfectMatch: 'false' })).toEqual({
@@ -26,6 +28,7 @@ describe('parseQueryToTypes', () => {
       modelId: undefined,
       backgroundId: undefined,
       initialPosition: { x: undefined, y: undefined, z: undefined },
+      overlaysId: undefined,
     });
 
     expect(parseQueryToTypes({ modelId: '666' })).toEqual({
@@ -34,6 +37,7 @@ describe('parseQueryToTypes', () => {
       modelId: 666,
       backgroundId: undefined,
       initialPosition: { x: undefined, y: undefined, z: undefined },
+      overlaysId: undefined,
     });
     expect(parseQueryToTypes({ x: '2137' })).toEqual({
       searchValue: undefined,
@@ -41,6 +45,7 @@ describe('parseQueryToTypes', () => {
       modelId: undefined,
       backgroundId: undefined,
       initialPosition: { x: 2137, y: undefined, z: undefined },
+      overlaysId: undefined,
     });
     expect(parseQueryToTypes({ y: '1372' })).toEqual({
       searchValue: undefined,
@@ -48,6 +53,7 @@ describe('parseQueryToTypes', () => {
       modelId: undefined,
       backgroundId: undefined,
       initialPosition: { x: undefined, y: 1372, z: undefined },
+      overlaysId: undefined,
     });
     expect(parseQueryToTypes({ z: '3721' })).toEqual({
       searchValue: undefined,
@@ -55,6 +61,16 @@ describe('parseQueryToTypes', () => {
       modelId: undefined,
       backgroundId: undefined,
       initialPosition: { x: undefined, y: undefined, z: 3721 },
+      overlaysId: undefined,
+    });
+    expect(parseQueryToTypes({ overlaysId: '1,2,3' })).toEqual({
+      searchValue: undefined,
+      perfectMatch: false,
+      modelId: undefined,
+      backgroundId: undefined,
+      initialPosition: { x: undefined, y: undefined, z: undefined },
+      // eslint-disable-next-line no-magic-numbers
+      overlaysId: [1, 2, 3],
     });
   });
 });
diff --git a/src/utils/parseQueryToTypes.ts b/src/utils/parseQueryToTypes.ts
index 9dc659c0..ee744037 100644
--- a/src/utils/parseQueryToTypes.ts
+++ b/src/utils/parseQueryToTypes.ts
@@ -10,4 +10,5 @@ export const parseQueryToTypes = (query: QueryDataRouterParams): QueryData => ({
     y: Number(query.y) || undefined,
     z: Number(query.z) || undefined,
   },
+  overlaysId: query.overlaysId?.split(',').map(Number),
 });
diff --git a/src/utils/query-manager/useReduxBusQueryManager.test.ts b/src/utils/query-manager/useReduxBusQueryManager.test.ts
index dc4bc4b6..77244318 100644
--- a/src/utils/query-manager/useReduxBusQueryManager.test.ts
+++ b/src/utils/query-manager/useReduxBusQueryManager.test.ts
@@ -25,6 +25,10 @@ describe('useReduxBusQueryManager - util', () => {
       data: [],
       loading: 'succeeded' as Loading,
       error: { name: '', message: '' },
+      addOverlay: {
+        loading: 'idle' as Loading,
+        error: { name: '', message: '' },
+      },
     };
 
     const { Wrapper } = getReduxWrapperWithStore({
-- 
GitLab