diff --git a/pages/_document.tsx b/pages/_document.tsx
index 94c6212c42688410055e35724e0b36852ff33ca3..c0d2fd720de69ef2881a040ff88fd8f9af85c952 100644
--- a/pages/_document.tsx
+++ b/pages/_document.tsx
@@ -8,6 +8,7 @@ const Document = (): React.ReactNode => (
     </Head>
     <body>
       <Main />
+      <div id="modal-root" />
       <NextScript />
       <Script src="./config.js" strategy="beforeInteractive" />
     </body>
diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
index b06a5fe7b5517c484fb9242e0d101157edc0f2b0..eab74a7e4fd30da041120e5731c0987b8720dc3e 100644
--- a/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
@@ -49,6 +49,7 @@ describe('EditOverlayModal - component', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
     });
 
@@ -67,6 +68,7 @@ describe('EditOverlayModal - component', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
     });
 
@@ -97,6 +99,7 @@ describe('EditOverlayModal - component', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -132,6 +135,7 @@ describe('EditOverlayModal - component', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -168,6 +172,7 @@ describe('EditOverlayModal - component', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -212,6 +217,7 @@ describe('EditOverlayModal - component', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -241,6 +247,7 @@ describe('EditOverlayModal - component', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
     });
 
diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
index 172a10260690e968f93774434a5223a1d57c0ccc..16f4307190235d6e03c4175b168b4b68fbc46e50 100644
--- a/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
@@ -24,6 +24,7 @@ describe('useEditOverlay', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
     });
 
@@ -60,6 +61,7 @@ describe('useEditOverlay', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
     });
 
@@ -99,6 +101,7 @@ describe('useEditOverlay', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
     });
 
@@ -134,6 +137,7 @@ describe('useEditOverlay', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
     });
 
@@ -170,6 +174,7 @@ describe('useEditOverlay', () => {
         molArtState: {},
         overviewImagesState: {},
         errorReportState: {},
+        layerFactoryState: { id: undefined },
       },
     });
 
diff --git a/src/components/FunctionalArea/Modal/LayerFactoryModal/LayerFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerFactoryModal/LayerFactoryModal.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..e8b7b95f30da6538a5ab3c25bd779fdbf849c9fa
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/LayerFactoryModal/LayerFactoryModal.component.test.tsx
@@ -0,0 +1,87 @@
+/* eslint-disable no-magic-numbers */
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import { StoreType } from '@/redux/store';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
+import { apiPath } from '@/redux/apiPath';
+import { HttpStatusCode } from 'axios';
+import { layerFixture } from '@/models/fixtures/layerFixture';
+import { layersFixture } from '@/models/fixtures/layersFixture';
+import { layerTextsFixture } from '@/models/fixtures/layerTextsFixture';
+import { layerRectsFixture } from '@/models/fixtures/layerRectsFixture';
+import { layerOvalsFixture } from '@/models/fixtures/layerOvalsFixture';
+import { layerLinesFixture } from '@/models/fixtures/layerLinesFixture';
+import { act } from 'react-dom/test-utils';
+import { LayerFactoryModal } from './LayerFactoryModal.component';
+
+const mockedAxiosNewClient = mockNetworkNewAPIResponse();
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <LayerFactoryModal />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('LayerFactoryModal - component', () => {
+  it('should render LayerFactoryModal component', () => {
+    renderComponent();
+
+    const name = screen.getByTestId('layer-factory-name');
+    const visible = screen.getByTestId('layer-factory-visible');
+    const locked = screen.getByTestId('layer-factory-locked');
+    expect(name).toBeInTheDocument();
+    expect(visible).toBeInTheDocument();
+    expect(locked).toBeInTheDocument();
+  });
+
+  it('should handles input change correctly', () => {
+    renderComponent();
+
+    const nameInput: HTMLInputElement = screen.getByTestId('layer-factory-name');
+
+    fireEvent.change(nameInput, { target: { value: 'test layer' } });
+
+    expect(nameInput.value).toBe('test layer');
+  });
+
+  it('should fetch layers when the form is  successfully submitted', async () => {
+    mockedAxiosNewClient.onPost(apiPath.storeLayer(0)).reply(HttpStatusCode.Ok, layerFixture);
+    mockedAxiosNewClient.onGet(apiPath.getLayers(0)).reply(HttpStatusCode.Ok, layersFixture);
+    mockedAxiosNewClient
+      .onGet(apiPath.getLayerTexts(0, layersFixture.content[0].id))
+      .reply(HttpStatusCode.Ok, layerTextsFixture);
+    mockedAxiosNewClient
+      .onGet(apiPath.getLayerRects(0, layersFixture.content[0].id))
+      .reply(HttpStatusCode.Ok, layerRectsFixture);
+    mockedAxiosNewClient
+      .onGet(apiPath.getLayerOvals(0, layersFixture.content[0].id))
+      .reply(HttpStatusCode.Ok, layerOvalsFixture);
+    mockedAxiosNewClient
+      .onGet(apiPath.getLayerLines(0, layersFixture.content[0].id))
+      .reply(HttpStatusCode.Ok, layerLinesFixture);
+
+    const { store } = renderComponent();
+    const nameInput: HTMLInputElement = screen.getByTestId('layer-factory-name');
+    const submitButton = screen.getByTestId('submit');
+
+    fireEvent.change(nameInput, { target: { value: 'test layer' } });
+    act(() => {
+      submitButton.click();
+    });
+    await waitFor(() => {
+      expect(store.getState().layers[0].loading).toBe('succeeded');
+    });
+  });
+});
diff --git a/src/components/FunctionalArea/Modal/LayerFactoryModal/LayerFactoryModal.component.tsx b/src/components/FunctionalArea/Modal/LayerFactoryModal/LayerFactoryModal.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..8d925951e04c0ed72650e50001e43f6b416d7038
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/LayerFactoryModal/LayerFactoryModal.component.tsx
@@ -0,0 +1,150 @@
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { Button } from '@/shared/Button';
+import { Input } from '@/shared/Input';
+import React, { useEffect, useMemo, useState } from 'react';
+
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { currentModelIdSelector } from '@/redux/models/models.selectors';
+import { closeModal } from '@/redux/modal/modal.slice';
+import { showToast } from '@/utils/showToast';
+import { Switch } from '@/shared/Switch';
+import { LayerStoreInterface, LayerUpdateInterface } from '@/redux/layers/layers.types';
+import {
+  addLayerForModel,
+  getLayer,
+  getLayersForModel,
+  updateLayer,
+} from '@/redux/layers/layers.thunks';
+import { SerializedError } from '@reduxjs/toolkit';
+import { layerFactoryStateSelector } from '@/redux/modal/modal.selector';
+import './LayerFactoryModal.styles.css';
+import { LoadingIndicator } from '@/shared/LoadingIndicator';
+
+export const LayerFactoryModal: React.FC = () => {
+  const dispatch = useAppDispatch();
+  const currentModelId = useAppSelector(currentModelIdSelector);
+  const layerFactoryState = useAppSelector(layerFactoryStateSelector);
+  const [loaded, setLoaded] = useState<boolean>(false);
+
+  const [data, setData] = useState<LayerStoreInterface>({
+    name: '',
+    visible: false,
+    locked: false,
+    modelId: currentModelId,
+  });
+
+  const fetchData = useMemo(() => {
+    return async (layerId: number): Promise<void> => {
+      const layer = await dispatch(getLayer({ modelId: currentModelId, layerId })).unwrap();
+      if (layer) {
+        setData({
+          name: layer.name,
+          visible: layer.visible,
+          locked: layer.locked,
+          modelId: currentModelId,
+        });
+      }
+      setLoaded(true);
+    };
+  }, [currentModelId, dispatch]);
+
+  useEffect(() => {
+    if (layerFactoryState.id) {
+      fetchData(layerFactoryState.id);
+    } else {
+      setLoaded(true);
+    }
+  }, [fetchData, layerFactoryState.id]);
+
+  const handleChange = (value: string | boolean, key: string): void => {
+    setData(prevData => ({ ...prevData, [key]: value }));
+  };
+
+  const handleSubmit = async (event: React.FormEvent<HTMLFormElement>): Promise<void> => {
+    try {
+      event.preventDefault();
+      if (layerFactoryState.id) {
+        const payload = {
+          ...data,
+          layerId: layerFactoryState.id,
+        } as LayerUpdateInterface;
+        await dispatch(updateLayer(payload)).unwrap();
+        showToast({
+          type: 'success',
+          message: 'The layer has been successfully updated',
+        });
+      } else {
+        await dispatch(addLayerForModel(data)).unwrap();
+        showToast({
+          type: 'success',
+          message: 'A new layer has been successfully added',
+        });
+      }
+      dispatch(closeModal());
+      dispatch(getLayersForModel(currentModelId));
+    } catch (error) {
+      const typedError = error as SerializedError;
+      showToast({
+        type: 'error',
+        message: typedError.message || 'An error occurred while adding a new layer',
+      });
+    }
+  };
+
+  return (
+    <div className="relative w-[400px] border border-t-[#E1E0E6] bg-white p-[24px]">
+      {!loaded && (
+        <div className="c-layer-factory-loader">
+          <LoadingIndicator width={44} height={44} />
+        </div>
+      )}
+      <form onSubmit={handleSubmit}>
+        <label className="mb-6 block text-sm font-semibold" htmlFor="name">
+          Name:
+          <Input
+            type="text"
+            id="name"
+            data-testid="layer-factory-name"
+            placeholder="Layer name here..."
+            value={data.name}
+            onChange={event => {
+              handleChange(event.target.value, 'name');
+            }}
+            className="mt-2.5 text-sm font-medium text-font-400"
+          />
+        </label>
+        <label
+          htmlFor="visible"
+          className="mb-6 flex items-center justify-between text-sm font-semibold"
+        >
+          Visible:
+          <Switch
+            id="visible"
+            data-testid="layer-factory-visible"
+            isChecked={data.visible}
+            onToggle={value => handleChange(value, 'visible')}
+          />
+        </label>
+        <label
+          htmlFor="locked"
+          className="mb-6 flex items-center justify-between text-sm font-semibold"
+        >
+          Locked:
+          <Switch
+            id="locked"
+            data-testid="layer-factory-locked"
+            isChecked={data.locked}
+            onToggle={value => handleChange(value, 'locked')}
+          />
+        </label>
+        <Button
+          type="submit"
+          className="w-full justify-center text-base font-medium"
+          data-testid="submit"
+        >
+          Submit
+        </Button>
+      </form>
+    </div>
+  );
+};
diff --git a/src/components/FunctionalArea/Modal/LayerFactoryModal/LayerFactoryModal.styles.css b/src/components/FunctionalArea/Modal/LayerFactoryModal/LayerFactoryModal.styles.css
new file mode 100644
index 0000000000000000000000000000000000000000..9178a2afb38e6e9ce79c9d41fef7f4df30347124
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/LayerFactoryModal/LayerFactoryModal.styles.css
@@ -0,0 +1,12 @@
+.c-layer-factory-loader {
+  width: 100%;
+  height: 100%;
+  margin-left: -24px;
+  margin-top: -24px;
+  background: #f9f9f980;
+  z-index: 1;
+  position: absolute;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
diff --git a/src/components/FunctionalArea/Modal/LayerFactoryModal/index.ts b/src/components/FunctionalArea/Modal/LayerFactoryModal/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5e9a93d6b02894c3adf8f457e960f5294142f17f
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/LayerFactoryModal/index.ts
@@ -0,0 +1 @@
+export { LayerFactoryModal } from './LayerFactoryModal.component';
diff --git a/src/components/FunctionalArea/Modal/Modal.component.tsx b/src/components/FunctionalArea/Modal/Modal.component.tsx
index 2768dfa3c5a4a66d968a6a7c3ce5ec61c4ea2c2a..8419791dee19ccf04d34e3c87eb731862356838d 100644
--- a/src/components/FunctionalArea/Modal/Modal.component.tsx
+++ b/src/components/FunctionalArea/Modal/Modal.component.tsx
@@ -12,6 +12,7 @@ import { ModalLayout } from './ModalLayout';
 import { OverviewImagesModal } from './OverviewImagesModal';
 import { PublicationsModal } from './PublicationsModal';
 import { LoggedInMenuModal } from './LoggedInMenuModal';
+import { LayerFactoryModal } from './LayerFactoryModal';
 
 const MolArtModal = dynamic(
   () => import('./MolArtModal/MolArtModal.component').then(mod => mod.MolArtModal),
@@ -79,6 +80,11 @@ export const Modal = (): React.ReactNode => {
           <AddCommentModal />
         </ModalLayout>
       )}
+      {isOpen && modalName === 'layer-factory' && (
+        <ModalLayout>
+          <LayerFactoryModal />
+        </ModalLayout>
+      )}
     </>
   );
 };
diff --git a/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx b/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx
index b202afcdc6c6088f8db048f00695235c4cbfe94d..493f2bc7a4be1a57cf5218ca7505075893746d29 100644
--- a/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx
+++ b/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx
@@ -33,6 +33,7 @@ export const ModalLayout = ({ children }: ModalLayoutProps): JSX.Element => {
             modalName === 'terms-of-service' && 'h-auto w-[400px]',
             modalName === 'add-comment' && 'h-auto w-[400px]',
             modalName === 'error-report' && 'h-auto w-[800px]',
+            modalName === 'layer-factory' && 'h-auto w-[400px]',
             ['edit-overlay', 'logged-in-menu'].includes(modalName) && 'h-auto w-[432px]',
           )}
         >
diff --git a/src/components/FunctionalArea/Modal/QuestionModal/Question.styles.css b/src/components/FunctionalArea/Modal/QuestionModal/Question.styles.css
new file mode 100644
index 0000000000000000000000000000000000000000..9d2ec888aac8c9e9d60262c8f3c5f50d368c85c6
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/QuestionModal/Question.styles.css
@@ -0,0 +1,27 @@
+.c-question-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 11;
+}
+
+.c-question-modal {
+  width: 400px;
+  height: auto;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  gap: 2rem;
+  background-color: #fff;
+  padding: 20px;
+  border-radius: 8px;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+  text-align: center;
+}
diff --git a/src/components/FunctionalArea/Modal/QuestionModal/QuestionModal.component.test.tsx b/src/components/FunctionalArea/Modal/QuestionModal/QuestionModal.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..556cf577558a9ee69e730ebce89c151bfbc96579
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/QuestionModal/QuestionModal.component.test.tsx
@@ -0,0 +1,58 @@
+/* eslint-disable no-magic-numbers */
+import React from 'react';
+import { render, screen, fireEvent } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import QuestionModal from './QustionModal.component';
+
+beforeEach(() => {
+  const modalRoot = document.createElement('div');
+  modalRoot.setAttribute('id', 'modal-root');
+  document.body.appendChild(modalRoot);
+});
+
+afterEach(() => {
+  const modalRoot = document.getElementById('modal-root');
+  if (modalRoot) {
+    document.body.removeChild(modalRoot);
+  }
+});
+
+describe('QuestionModal', () => {
+  const defaultProps = {
+    isOpen: true,
+    onClose: jest.fn(),
+    onConfirm: jest.fn(),
+    question: 'Are you sure?',
+  };
+
+  it('should not render when isOpen is false', () => {
+    render(<QuestionModal {...defaultProps} isOpen={false} />);
+    const modalContent = screen.queryByText(defaultProps.question);
+    expect(modalContent).not.toBeInTheDocument();
+  });
+
+  it('should render the question when isOpen is true', () => {
+    render(<QuestionModal {...defaultProps} />);
+    expect(screen.getByText('Are you sure?')).toBeInTheDocument();
+  });
+
+  it('should call onClose when "No" button is clicked', () => {
+    render(<QuestionModal {...defaultProps} />);
+    const noButton = screen.getByText('No');
+    fireEvent.click(noButton);
+    expect(defaultProps.onClose).toHaveBeenCalledTimes(1);
+  });
+
+  it('should call onConfirm when "Yes" button is clicked', () => {
+    render(<QuestionModal {...defaultProps} />);
+    const yesButton = screen.getByText('Yes');
+    fireEvent.click(yesButton);
+    expect(defaultProps.onConfirm).toHaveBeenCalledTimes(1);
+  });
+
+  it('should render inside the modal-root portal', () => {
+    render(<QuestionModal {...defaultProps} />);
+    const modalRoot = document.getElementById('modal-root');
+    expect(modalRoot).toContainElement(screen.getByText('Are you sure?'));
+  });
+});
diff --git a/src/components/FunctionalArea/Modal/QuestionModal/QustionModal.component.tsx b/src/components/FunctionalArea/Modal/QuestionModal/QustionModal.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..3f7f3db7df221087945e5c0c2bdedc0191b6e637
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/QuestionModal/QustionModal.component.tsx
@@ -0,0 +1,56 @@
+import React, { ReactPortal } from 'react';
+import ReactDOM from 'react-dom';
+import { Button } from '@/shared/Button';
+import './Question.styles.css';
+import { QuestionIcon } from '@/shared/Icon/Icons/QuestionIcon';
+
+type QuestionModalProps = {
+  isOpen: boolean;
+  onClose: () => void;
+  onConfirm: () => void;
+  question: string;
+};
+
+const QuestionModal = ({
+  isOpen,
+  onClose,
+  onConfirm,
+  question,
+}: QuestionModalProps): null | ReactPortal => {
+  if (!isOpen) return null;
+
+  const domElement = document.getElementById('modal-root');
+
+  if (!domElement) {
+    return null;
+  }
+
+  return ReactDOM.createPortal(
+    <div className="c-question-overlay">
+      <div className="c-question-modal">
+        <QuestionIcon size={94} />
+        <h1 className="text-center text-2xl font-semibold">{question}</h1>
+        <div className="flex w-full justify-center gap-10">
+          <Button
+            type="submit"
+            className="w-[100px] justify-center text-base font-medium"
+            variantStyles="remove"
+            onClick={onClose}
+          >
+            No
+          </Button>
+          <Button
+            type="submit"
+            className="w-[100px] justify-center text-base font-medium"
+            onClick={onConfirm}
+          >
+            Yes
+          </Button>
+        </div>
+      </div>
+    </div>,
+    domElement,
+  );
+};
+
+export default QuestionModal;
diff --git a/src/components/Map/Drawer/BioEntityDrawer/ChemicalsList/ChemicalsList.component.test.tsx b/src/components/Map/Drawer/BioEntityDrawer/ChemicalsList/ChemicalsList.component.test.tsx
index 03adc8fd596b1a8890cdd2163b0adbb9c03c27bb..c40c8c87a405cfccfdfa1987727c5c4d02a96d5f 100644
--- a/src/components/Map/Drawer/BioEntityDrawer/ChemicalsList/ChemicalsList.component.test.tsx
+++ b/src/components/Map/Drawer/BioEntityDrawer/ChemicalsList/ChemicalsList.component.test.tsx
@@ -47,7 +47,7 @@ describe('ChemicalsList - component', () => {
     });
 
     it('should show loading indicator', () => {
-      expect(screen.getByAltText('spinner icon')).toBeInTheDocument();
+      expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
     });
   });
 
diff --git a/src/components/Map/Drawer/BioEntityDrawer/DrugsList/DrugsList.component.test.tsx b/src/components/Map/Drawer/BioEntityDrawer/DrugsList/DrugsList.component.test.tsx
index 0ec503c4738362835d851bfd95d0fe0e10f08c54..b04ddbab442fcb95a8999d7e9412c7e0b9362358 100644
--- a/src/components/Map/Drawer/BioEntityDrawer/DrugsList/DrugsList.component.test.tsx
+++ b/src/components/Map/Drawer/BioEntityDrawer/DrugsList/DrugsList.component.test.tsx
@@ -47,7 +47,7 @@ describe('DrugsList - component', () => {
     });
 
     it('should show loading indicator', () => {
-      expect(screen.getByAltText('spinner icon')).toBeInTheDocument();
+      expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
     });
   });
 
diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx
index e5f914e8c2dc8d5947b08817359eba144b923218..b431590cad9fd0aca469b6b22e6d1345a69fe8b5 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx
@@ -8,32 +8,103 @@ import {
 import { Switch } from '@/shared/Switch';
 import { setLayerVisibility } from '@/redux/layers/layers.slice';
 import { currentModelIdSelector } from '@/redux/models/models.selectors';
+import { Button } from '@/shared/Button';
+import { openLayerFactoryModal } from '@/redux/modal/modal.slice';
+import QuestionModal from '@/components/FunctionalArea/Modal/QuestionModal/QustionModal.component';
+import { useState } from 'react';
+import { getLayersForModel, removeLayer } from '@/redux/layers/layers.thunks';
+import { showToast } from '@/utils/showToast';
+import { SerializedError } from '@reduxjs/toolkit';
 
 export const LayersDrawer = (): JSX.Element => {
   const layersForCurrentModel = useAppSelector(layersForCurrentModelSelector);
   const layersVisibilityForCurrentModel = useAppSelector(layersVisibilityForCurrentModelSelector);
   const currentModelId = useAppSelector(currentModelIdSelector);
   const dispatch = useAppDispatch();
+  const [isModalOpen, setIsModalOpen] = useState(false);
+  const [layerId, setLayerId] = useState<number | null>(null);
+
+  const addNewLayer = (): void => {
+    dispatch(openLayerFactoryModal());
+  };
+
+  const editLayer = (layerIdToEdit: number): void => {
+    dispatch(openLayerFactoryModal(layerIdToEdit));
+  };
+
+  const rejectRemove = (): void => {
+    setIsModalOpen(false);
+  };
+
+  const confirmRemove = async (): Promise<void> => {
+    if (!layerId) {
+      return;
+    }
+    try {
+      await dispatch(removeLayer({ modelId: currentModelId, layerId })).unwrap();
+      showToast({
+        type: 'success',
+        message: 'The layer has been successfully removed',
+      });
+      setIsModalOpen(false);
+      dispatch(getLayersForModel(currentModelId));
+    } catch (error) {
+      const typedError = error as SerializedError;
+      showToast({
+        type: 'error',
+        message: typedError.message || 'An error occurred while removing the layer',
+      });
+    }
+  };
+
+  const onRemoveLayer = (layerIdToRemove: number): void => {
+    setLayerId(layerIdToRemove);
+    setIsModalOpen(true);
+  };
 
   return (
     <div data-testid="layers-drawer" className="h-full max-h-full">
+      <QuestionModal
+        isOpen={isModalOpen}
+        onClose={rejectRemove}
+        onConfirm={confirmRemove}
+        question="Are you sure you want to remove the layer?"
+      />
       <DrawerHeading title="Layers" />
       <div className="flex h-[calc(100%-93px)] max-h-[calc(100%-93px)] flex-col overflow-y-auto px-6">
+        <div className="flex justify-start pt-2">
+          <Button icon="plus" isIcon isFrontIcon onClick={addNewLayer}>
+            Add new layer
+          </Button>
+        </div>
         {layersForCurrentModel.map(layer => (
-          <div key={layer.details.id} className="flex items-center justify-between border-b p-4">
-            <h1>{layer.details.name}</h1>
-            <Switch
-              isChecked={layersVisibilityForCurrentModel[layer.details.id]}
-              onToggle={value =>
-                dispatch(
-                  setLayerVisibility({
-                    modelId: currentModelId,
-                    visible: value,
-                    layerId: layer.details.id,
-                  }),
-                )
-              }
-            />
+          <div
+            key={layer.details.id}
+            className="flex items-center justify-between gap-3 border-b py-4"
+          >
+            <h1 className="truncate">{layer.details.name}</h1>
+            <div className="flex items-center gap-2">
+              <Switch
+                isChecked={layersVisibilityForCurrentModel[layer.details.id]}
+                onToggle={value =>
+                  dispatch(
+                    setLayerVisibility({
+                      modelId: currentModelId,
+                      visible: value,
+                      layerId: layer.details.id,
+                    }),
+                  )
+                }
+              />
+              <Button onClick={() => editLayer(layer.details.id)}>Edit</Button>
+              <Button
+                onClick={() => onRemoveLayer(layer.details.id)}
+                color="error"
+                variantStyles="remove"
+              >
+                Remove
+              </Button>
+            </div>
           </div>
         ))}
       </div>
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.test.ts
index 46baee4385088e620a5170c6bde5521d95ee497f..4fd1b57f0e0bc4800ad6492d5f75ce917b684abf 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.test.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.test.ts
@@ -44,10 +44,7 @@ describe('Layer', () => {
           width: 100,
           height: 100,
           fontSize: 12,
-          size: 12312,
           notes: 'XYZ',
-          glyph: null,
-          elementId: '34',
           verticalAlign: 'MIDDLE',
           horizontalAlign: 'CENTER',
           backgroundColor: WHITE_COLOR,
diff --git a/src/models/fixtures/layerFixture.ts b/src/models/fixtures/layerFixture.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9f9d4843e675c49e81da406bb38ac67a083bd4c2
--- /dev/null
+++ b/src/models/fixtures/layerFixture.ts
@@ -0,0 +1,9 @@
+import { ZOD_SEED } from '@/constants';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { createFixture } from 'zod-fixture';
+import { layerSchema } from '@/models/layerSchema';
+
+export const layerFixture = createFixture(layerSchema, {
+  seed: ZOD_SEED,
+  array: { min: 1, max: 1 },
+});
diff --git a/src/models/layerTextSchema.ts b/src/models/layerTextSchema.ts
index 3ad77ed0e59946a8a2a8586eb8ab8b237e67f618..6858da82cc89c2f05336b3cdfb7b5b49df1a34e7 100644
--- a/src/models/layerTextSchema.ts
+++ b/src/models/layerTextSchema.ts
@@ -1,6 +1,5 @@
 import { z } from 'zod';
 import { colorSchema } from '@/models/colorSchema';
-import { glyphSchema } from '@/models/glyphSchema';
 
 export const layerTextSchema = z.object({
   id: z.number(),
@@ -10,10 +9,7 @@ export const layerTextSchema = z.object({
   width: z.number(),
   height: z.number(),
   fontSize: z.number(),
-  size: z.number(),
   notes: z.string(),
-  glyph: glyphSchema.nullable(),
-  elementId: z.string(),
   verticalAlign: z.string(),
   horizontalAlign: z.string(),
   backgroundColor: colorSchema,
diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts
index 174debec841ae0734109a7fd667afa1a63eae971..760ccb7a5e8dc3391fed144af0cd6977205c3c20 100644
--- a/src/redux/apiPath.ts
+++ b/src/redux/apiPath.ts
@@ -58,6 +58,13 @@ export const apiPath = {
     `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/ovals/`,
   getLayerLines: (modelId: number, layerId: number): string =>
     `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/lines/`,
+  storeLayer: (modelId: number): string => `projects/${PROJECT_ID}/maps/${modelId}/layers/`,
+  updateLayer: (modelId: number, layerId: number): string =>
+    `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}`,
+  removeLayer: (modelId: number, layerId: number): string =>
+    `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}`,
+  getLayer: (modelId: number, layerId: number): string =>
+    `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}`,
   getGlyphImage: (glyphId: number): string =>
     `projects/${PROJECT_ID}/glyphs/${glyphId}/fileContent`,
   getNewReactionsForModel: (modelId: number): string =>
diff --git a/src/redux/layers/layers.thunks.test.ts b/src/redux/layers/layers.thunks.test.ts
index 234d9950d59c21be0a60a830d4ce7e8cfc755db8..c8b9b2bcc44d00428e0b3adaf11150d159774c21 100644
--- a/src/redux/layers/layers.thunks.test.ts
+++ b/src/redux/layers/layers.thunks.test.ts
@@ -7,12 +7,19 @@ import {
 import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
 import { HttpStatusCode } from 'axios';
 import { LayersState } from '@/redux/layers/layers.types';
-import { getLayersForModel } from '@/redux/layers/layers.thunks';
+import {
+  addLayerForModel,
+  getLayer,
+  getLayersForModel,
+  removeLayer,
+  updateLayer,
+} from '@/redux/layers/layers.thunks';
 import { layersFixture } from '@/models/fixtures/layersFixture';
 import { layerTextsFixture } from '@/models/fixtures/layerTextsFixture';
 import { layerRectsFixture } from '@/models/fixtures/layerRectsFixture';
 import { layerOvalsFixture } from '@/models/fixtures/layerOvalsFixture';
 import { layerLinesFixture } from '@/models/fixtures/layerLinesFixture';
+import { layerFixture } from '@/models/fixtures/layerFixture';
 import layersReducer from './layers.slice';
 
 const mockedAxiosClient = mockNetworkNewAPIResponse();
@@ -65,4 +72,85 @@ describe('layers thunks', () => {
       expect(payload).toEqual(undefined);
     });
   });
+
+  describe('getLayer', () => {
+    it('should return a layer when data is valid', async () => {
+      mockedAxiosClient.onGet(apiPath.getLayer(1, 2)).reply(HttpStatusCode.Ok, layerFixture);
+
+      const { payload } = await store.dispatch(getLayer({ modelId: 1, layerId: 2 }));
+      expect(payload).toEqual(layerFixture);
+    });
+
+    it('should return null when data is invalid', async () => {
+      mockedAxiosClient.onGet(apiPath.getLayer(1, 2)).reply(HttpStatusCode.Ok, { invalid: 'data' });
+
+      const { payload } = await store.dispatch(getLayer({ modelId: 1, layerId: 2 }));
+      expect(payload).toBeNull();
+    });
+  });
+
+  describe('addLayerForModel', () => {
+    it('should add a layer when data is valid', async () => {
+      mockedAxiosClient.onPost(apiPath.storeLayer(1)).reply(HttpStatusCode.Created, layerFixture);
+
+      const { payload } = await store.dispatch(
+        addLayerForModel({ name: 'New Layer', visible: true, locked: false, modelId: 1 }),
+      );
+      expect(payload).toEqual(layerFixture);
+    });
+
+    it('should return null when response data is invalid', async () => {
+      mockedAxiosClient
+        .onPost(apiPath.storeLayer(1))
+        .reply(HttpStatusCode.Created, { invalid: 'data' });
+
+      const { payload } = await store.dispatch(
+        addLayerForModel({ name: 'New Layer', visible: true, locked: false, modelId: 1 }),
+      );
+      expect(payload).toBeNull();
+    });
+  });
+
+  describe('updateLayer', () => {
+    it('should update a layer successfully', async () => {
+      mockedAxiosClient.onPut(apiPath.updateLayer(1, 2)).reply(HttpStatusCode.Ok, layerFixture);
+
+      const { payload } = await store.dispatch(
+        updateLayer({
+          name: 'Updated Layer',
+          visible: false,
+          locked: true,
+          modelId: 1,
+          layerId: 2,
+        }),
+      );
+      expect(payload).toEqual(layerFixture);
+    });
+
+    it('should return null for invalid data', async () => {
+      mockedAxiosClient
+        .onPut(apiPath.updateLayer(1, 2))
+        .reply(HttpStatusCode.Ok, { invalid: 'data' });
+
+      const { payload } = await store.dispatch(
+        updateLayer({
+          name: 'Updated Layer',
+          visible: false,
+          locked: true,
+          modelId: 1,
+          layerId: 2,
+        }),
+      );
+      expect(payload).toBeNull();
+    });
+  });
+
+  describe('removeLayer', () => {
+    it('should successfully remove a layer', async () => {
+      mockedAxiosClient.onDelete(apiPath.removeLayer(1, 2)).reply(HttpStatusCode.NoContent);
+
+      const result = await store.dispatch(removeLayer({ modelId: 1, layerId: 2 }));
+      expect(result.meta.requestStatus).toBe('fulfilled');
+    });
+  });
 });
diff --git a/src/redux/layers/layers.thunks.ts b/src/redux/layers/layers.thunks.ts
index f1594875f0597b512a6e8d6c4b4becb063ac8425..c8ee4fd5abbac494634b2a881df5c5b6c4f2fb4c 100644
--- a/src/redux/layers/layers.thunks.ts
+++ b/src/redux/layers/layers.thunks.ts
@@ -8,13 +8,33 @@ import { getError } from '@/utils/error-report/getError';
 import { axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance';
 import { layerSchema } from '@/models/layerSchema';
 import { LAYERS_FETCHING_ERROR_PREFIX } from '@/redux/layers/layers.constants';
-import { LayersVisibilitiesState } from '@/redux/layers/layers.types';
+import {
+  LayerStoreInterface,
+  LayersVisibilitiesState,
+  LayerUpdateInterface,
+} from '@/redux/layers/layers.types';
 import { layerTextSchema } from '@/models/layerTextSchema';
 import { layerRectSchema } from '@/models/layerRectSchema';
 import { pageableSchema } from '@/models/pageableSchema';
 import { layerOvalSchema } from '@/models/layerOvalSchema';
 import { layerLineSchema } from '@/models/layerLineSchema';
 
+export const getLayer = createAsyncThunk<
+  Layer | null,
+  { modelId: number; layerId: number },
+  ThunkConfig
+>('vectorMap/getLayer', async ({ modelId, layerId }) => {
+  try {
+    const { data } = await axiosInstanceNewAPI.get<Layer>(apiPath.getLayer(modelId, layerId));
+
+    const isDataValid = validateDataUsingZodSchema(data, layerSchema);
+
+    return isDataValid ? data : null;
+  } catch (error) {
+    return Promise.reject(getError({ error }));
+  }
+});
+
 export const getLayersForModel = createAsyncThunk<
   LayersVisibilitiesState | undefined,
   number,
@@ -64,3 +84,54 @@ export const getLayersForModel = createAsyncThunk<
     return Promise.reject(getError({ error, prefix: LAYERS_FETCHING_ERROR_PREFIX }));
   }
 });
+
+export const addLayerForModel = createAsyncThunk<Layer | null, LayerStoreInterface, ThunkConfig>(
+  'vectorMap/addLayer',
+  async ({ name, visible, locked, modelId }) => {
+    try {
+      const { data } = await axiosInstanceNewAPI.post<Layer>(apiPath.storeLayer(modelId), {
+        name,
+        visible,
+        locked,
+      });
+
+      const isDataValid = validateDataUsingZodSchema(data, layerSchema);
+
+      return isDataValid ? data : null;
+    } catch (error) {
+      return Promise.reject(getError({ error }));
+    }
+  },
+);
+
+export const updateLayer = createAsyncThunk<Layer | null, LayerUpdateInterface, ThunkConfig>(
+  'vectorMap/updateLayer',
+  async ({ name, visible, locked, modelId, layerId }) => {
+    try {
+      const { data } = await axiosInstanceNewAPI.put<Layer>(apiPath.updateLayer(modelId, layerId), {
+        name,
+        visible,
+        locked,
+      });
+
+      const isDataValid = validateDataUsingZodSchema(data, layerSchema);
+
+      return isDataValid ? data : null;
+    } catch (error) {
+      return Promise.reject(getError({ error }));
+    }
+  },
+);
+
+export const removeLayer = createAsyncThunk<
+  void,
+  { modelId: number; layerId: number },
+  ThunkConfig
+  // eslint-disable-next-line consistent-return
+>('vectorMap/removeLayer', async ({ modelId, layerId }) => {
+  try {
+    await axiosInstanceNewAPI.delete<void>(apiPath.removeLayer(modelId, layerId));
+  } catch (error) {
+    return Promise.reject(getError({ error }));
+  }
+});
diff --git a/src/redux/layers/layers.types.ts b/src/redux/layers/layers.types.ts
index 701a499abc9979cc38b900ce64d25943a58935ef..a5c1b30e1f7f1978e447831649ec8896c3b92eeb 100644
--- a/src/redux/layers/layers.types.ts
+++ b/src/redux/layers/layers.types.ts
@@ -1,6 +1,21 @@
 import { KeyedFetchDataState } from '@/types/fetchDataState';
 import { Layer, LayerLine, LayerOval, LayerRect, LayerText } from '@/types/models';
 
+export interface LayerStoreInterface {
+  name: string;
+  visible: boolean;
+  locked: boolean;
+  modelId: number;
+}
+
+export interface LayerUpdateInterface {
+  layerId: number;
+  name: string;
+  visible: boolean;
+  locked: boolean;
+  modelId: number;
+}
+
 export type LayerState = {
   details: Layer;
   texts: LayerText[];
diff --git a/src/redux/modal/modal.constants.ts b/src/redux/modal/modal.constants.ts
index d7dea45c423398a99180fcd4151255ad93489fdf..1184d4ed526038773f9bb90853e52d8f0912dece 100644
--- a/src/redux/modal/modal.constants.ts
+++ b/src/redux/modal/modal.constants.ts
@@ -13,4 +13,5 @@ export const MODAL_INITIAL_STATE: ModalState = {
   },
   editOverlayState: null,
   errorReportState: {},
+  layerFactoryState: { id: undefined },
 };
diff --git a/src/redux/modal/modal.mock.ts b/src/redux/modal/modal.mock.ts
index cde5fab5cc156a2783af5987006fc87e499f7477..1a7a519f3509c02ae667c7e310eeb58af77c3af2 100644
--- a/src/redux/modal/modal.mock.ts
+++ b/src/redux/modal/modal.mock.ts
@@ -13,4 +13,5 @@ export const MODAL_INITIAL_STATE_MOCK: ModalState = {
   },
   editOverlayState: null,
   errorReportState: {},
+  layerFactoryState: { id: undefined },
 };
diff --git a/src/redux/modal/modal.reducers.ts b/src/redux/modal/modal.reducers.ts
index a3704696a08a6a8531a19b5e0d23cecc1ea095ae..3371ed3c102a74f1f32e8b26807291c159ac751c 100644
--- a/src/redux/modal/modal.reducers.ts
+++ b/src/redux/modal/modal.reducers.ts
@@ -124,3 +124,17 @@ export const openToSModalReducer = (state: ModalState): void => {
   state.modalName = 'terms-of-service';
   state.modalTitle = 'Terms of service!';
 };
+
+export const openLayerFactoryModalReducer = (
+  state: ModalState,
+  action: PayloadAction<number | undefined>,
+): void => {
+  state.layerFactoryState = { id: action.payload };
+  state.isOpen = true;
+  state.modalName = 'layer-factory';
+  if (action.payload) {
+    state.modalTitle = 'Edit layer';
+  } else {
+    state.modalTitle = 'Add new layer';
+  }
+};
diff --git a/src/redux/modal/modal.selector.ts b/src/redux/modal/modal.selector.ts
index 654dfb7aeac4b0b43a89cb676a92b9bf7d09922d..7f7c444111a45551d76fa8b41f887e9ceb43fe4b 100644
--- a/src/redux/modal/modal.selector.ts
+++ b/src/redux/modal/modal.selector.ts
@@ -21,6 +21,11 @@ export const currentEditedOverlaySelector = createSelector(
   modal => modal.editOverlayState,
 );
 
+export const layerFactoryStateSelector = createSelector(
+  modalSelector,
+  modal => modal.layerFactoryState,
+);
+
 export const currentErrorDataSelector = createSelector(
   modalSelector,
   modal => modal?.errorReportState.errorData || undefined,
diff --git a/src/redux/modal/modal.slice.ts b/src/redux/modal/modal.slice.ts
index bb145852246d450ffde3acb6e935f77eaac280f6..8ed0421510457f64c783b7c0548d09977f7e8415 100644
--- a/src/redux/modal/modal.slice.ts
+++ b/src/redux/modal/modal.slice.ts
@@ -16,6 +16,7 @@ import {
   openSelectProjectModalReducer,
   openLicenseModalReducer,
   openToSModalReducer,
+  openLayerFactoryModalReducer,
 } from './modal.reducers';
 
 const modalSlice = createSlice({
@@ -37,6 +38,7 @@ const modalSlice = createSlice({
     openSelectProjectModal: openSelectProjectModalReducer,
     openLicenseModal: openLicenseModalReducer,
     openToSModal: openToSModalReducer,
+    openLayerFactoryModal: openLayerFactoryModalReducer,
   },
 });
 
@@ -56,6 +58,7 @@ export const {
   openSelectProjectModal,
   openLicenseModal,
   openToSModal,
+  openLayerFactoryModal,
 } = modalSlice.actions;
 
 export default modalSlice.reducer;
diff --git a/src/redux/modal/modal.types.ts b/src/redux/modal/modal.types.ts
index ea77209610093378c152d5d114f41bc475bd97fb..1b544f5282525ca4e9b1d6efa3835c0e175313d4 100644
--- a/src/redux/modal/modal.types.ts
+++ b/src/redux/modal/modal.types.ts
@@ -17,6 +17,10 @@ export type ErrorRepostState = {
 
 export type EditOverlayState = MapOverlay | null;
 
+export type LayerFactoryState = {
+  id: number | undefined;
+};
+
 export interface ModalState {
   isOpen: boolean;
   modalName: ModalName;
@@ -25,6 +29,7 @@ export interface ModalState {
   molArtState: MolArtModalState;
   errorReportState: ErrorRepostState;
   editOverlayState: EditOverlayState;
+  layerFactoryState: LayerFactoryState;
 }
 
 export type OpenEditOverlayModalPayload = MapOverlay;
diff --git a/src/shared/Button/Button.component.tsx b/src/shared/Button/Button.component.tsx
index a7f831e7ed22cdc6c8ad17dafd1563375b27144e..72833322b47bc752812ebca40b6e60f6d4f9ebe6 100644
--- a/src/shared/Button/Button.component.tsx
+++ b/src/shared/Button/Button.component.tsx
@@ -4,7 +4,7 @@ import { twMerge } from 'tailwind-merge';
 import type { ButtonHTMLAttributes } from 'react';
 import type { IconTypes } from '@/types/iconTypes';
 
-type VariantStyle = 'primary' | 'secondary' | 'ghost' | 'quiet';
+type VariantStyle = 'primary' | 'secondary' | 'ghost' | 'quiet' | 'remove';
 
 export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
   variantStyles?: VariantStyle;
@@ -34,6 +34,11 @@ const variants = {
       'text-font-500 bg-white-pearl hover:bg-greyscale-500 active:bg-greyscale-600 disabled:text-font-400 disabled:bg-white-pearl',
     icon: 'fill-font-500 group-disabled:fill-font-400',
   },
+  remove: {
+    button:
+      'text-white-pearl bg-red-500 hover:bg-red-600 active:bg-red-700 disabled:bg-greyscale-700',
+    icon: 'fill-white-pearl',
+  },
 } as const;
 
 export const Button = ({
diff --git a/src/shared/Icon/Icon.component.tsx b/src/shared/Icon/Icon.component.tsx
index 634569549c9d5375d469e1e2c3208a63798986c2..f22e882b052efc6e3c7c5d63836d015d210cf88b 100644
--- a/src/shared/Icon/Icon.component.tsx
+++ b/src/shared/Icon/Icon.component.tsx
@@ -8,6 +8,7 @@ import { CloseIcon } from '@/shared/Icon/Icons/CloseIcon';
 import { DotsIcon } from '@/shared/Icon/Icons/DotsIcon';
 import { ExportIcon } from '@/shared/Icon/Icons/ExportIcon';
 import { LayersIcon } from '@/shared/Icon/Icons/LayersIcon';
+import { QuestionIcon } from '@/shared/Icon/Icons/QuestionIcon';
 import { InfoIcon } from '@/shared/Icon/Icons/InfoIcon';
 import { LegendIcon } from '@/shared/Icon/Icons/LegendIcon';
 import { PageIcon } from '@/shared/Icon/Icons/PageIcon';
@@ -43,6 +44,7 @@ const icons: Record<IconTypes, IconComponentType> = {
   admin: AdminIcon,
   export: ExportIcon,
   layers: LayersIcon,
+  question: QuestionIcon,
   info: InfoIcon,
   download: DownloadIcon,
   legend: LegendIcon,
diff --git a/src/shared/Icon/Icons/QuestionIcon.tsx b/src/shared/Icon/Icons/QuestionIcon.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..9deb22425f73443b9177f2eb666992bb3199a595
--- /dev/null
+++ b/src/shared/Icon/Icons/QuestionIcon.tsx
@@ -0,0 +1,23 @@
+/* eslint-disable no-magic-numbers */
+interface QuestionIconProps {
+  className?: string;
+  size?: number;
+}
+
+export const QuestionIcon = ({ className, size = 20 }: QuestionIconProps): JSX.Element => (
+  <svg
+    width={size}
+    height={size}
+    viewBox="0 0 100 100"
+    fill="none"
+    className={className}
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <circle cx="50" cy="50" r="44" stroke="black" strokeWidth="2" fill="none" />
+    <path
+      d="M50 80a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm1-20H47c0-6.6 3.6-8.8 6.6-10.9 3.4-2.3 5.4-4.5 5.4-8.1 0-5.5-4.5-10-10-10s-10 4.5-10 10H33c0-9.4 7.6-17 17-17s17 7.6 17 17c0 5.5-3.3 8.6-6.9 11.1-2.6 1.7-4.1 3.3-4.1 6.9z"
+      fill="black"
+      strokeWidth={1}
+    />
+  </svg>
+);
diff --git a/src/shared/LoadingIndicator/LoadingIndicator.component.tsx b/src/shared/LoadingIndicator/LoadingIndicator.component.tsx
index 39a2a4139dc58b06f7a71f810502a126e71d56f0..e63f02674e6e7b03a03cd51dc94454a714c59800 100644
--- a/src/shared/LoadingIndicator/LoadingIndicator.component.tsx
+++ b/src/shared/LoadingIndicator/LoadingIndicator.component.tsx
@@ -1,6 +1,3 @@
-import Image from 'next/image';
-import spinnerIcon from '@/assets/vectors/icons/spinner.svg';
-
 type LoadingIndicatorProps = {
   height?: number;
   width?: number;
@@ -13,12 +10,19 @@ export const LoadingIndicator = ({
   height = DEFAULT_HEIGHT,
   width = DEFAULT_WIDTH,
 }: LoadingIndicatorProps): JSX.Element => (
-  <Image
-    src={spinnerIcon}
-    alt="spinner icon"
-    height={height}
-    width={width}
-    className="animate-spin"
-    data-testid="loading-indicator"
-  />
+  <div style={{ width, height }} className="animate-spin" data-testid="loading-indicator">
+    <svg width={width} height={height} viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
+      <circle
+        cx="25"
+        cy="25"
+        r="20"
+        fill="none"
+        stroke="currentColor"
+        strokeWidth="4"
+        strokeDasharray="90, 150"
+        strokeDashoffset="0"
+        strokeLinecap="round"
+      />
+    </svg>
+  </div>
 );
diff --git a/src/shared/Switch/Switch.component.tsx b/src/shared/Switch/Switch.component.tsx
index 355e84b92d9aaf3e49ab8f0c41d01e8ee28037b8..b519870e93b302b01a66a664aac321fe5d00706c 100644
--- a/src/shared/Switch/Switch.component.tsx
+++ b/src/shared/Switch/Switch.component.tsx
@@ -1,12 +1,13 @@
 import { twMerge } from 'tailwind-merge';
-import { useEffect, useState } from 'react';
+import { type ButtonHTMLAttributes, useEffect, useState } from 'react';
 
 type VariantStyle = 'primary' | 'secondary' | 'ghost' | 'quiet';
 
-export interface SwitchProps {
+export interface SwitchProps extends ButtonHTMLAttributes<HTMLButtonElement> {
   variantStyles?: VariantStyle;
   isChecked?: boolean;
   onToggle?: (checked: boolean) => void;
+  id?: string;
 }
 
 const variants = {
@@ -32,6 +33,8 @@ export const Switch = ({
   variantStyles = 'primary',
   isChecked = false,
   onToggle,
+  id,
+  ...props
 }: SwitchProps): JSX.Element => {
   const [checked, setChecked] = useState(isChecked);
 
@@ -49,6 +52,7 @@ export const Switch = ({
 
   return (
     <button
+      id={id}
       type="button"
       className={twMerge(
         'relative inline-flex h-5 w-10 cursor-pointer rounded-full transition-colors duration-300 ease-in-out',
@@ -56,6 +60,7 @@ export const Switch = ({
         checked ? 'bg-primary-600' : '',
       )}
       onClick={handleToggle}
+      {...props}
     >
       <span
         className={twMerge(
diff --git a/src/types/iconTypes.ts b/src/types/iconTypes.ts
index 5000d642307404c19565b28b421a461d6729e859..7681839461a42db984af5556529f30e0ed4a57b0 100644
--- a/src/types/iconTypes.ts
+++ b/src/types/iconTypes.ts
@@ -23,6 +23,7 @@ export type IconTypes =
   | 'clear'
   | 'user'
   | 'manage-user'
-  | 'download';
+  | 'download'
+  | 'question';
 
 export type IconComponentType = ({ className }: { className: string }) => JSX.Element;
diff --git a/src/types/modal.ts b/src/types/modal.ts
index eaf3a498c59005f9a2b5c2f2470305970f2e07dc..861bb29569581cb89fcc57b136a3ff7cd8c2dcfc 100644
--- a/src/types/modal.ts
+++ b/src/types/modal.ts
@@ -11,4 +11,5 @@ export type ModalName =
   | 'access-denied'
   | 'select-project'
   | 'terms-of-service'
-  | 'logged-in-menu';
+  | 'logged-in-menu'
+  | 'layer-factory';