Index: imaps-frontend/src/scripts/base/MapNode.js
===================================================================
--- imaps-frontend/src/scripts/base/MapNode.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/base/MapNode.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,99 @@
+import MapShape from "./MapShape.js";
+import Konva from "konva";
+
+export default class MapNode extends MapShape{
+
+    constructor(config, layer, blockSize, snap) {
+        if (new.target === MapNode) {
+            throw new Error("Cannot instantiate abstract class NodeShape directly.");
+        }
+
+        super(config,layer,blockSize,snap);
+        this.connectionLines = [];
+
+        this.connLine = new Konva.Line({
+            stroke: "rgba(245,37,37,0.85)",
+            dash: [2,3],
+            strokeWidth: 2,
+            lineCap: 'round',
+            lineJoin: 'miter',
+            opacity: 0.8
+        });
+        this.connLine.cache();
+
+        this.on("dragmove",() => {
+            this.connectionLines.forEach(lineWrapper => {
+                console.log("other",lineWrapper.otherShape)
+                let updatedPoints = [this.x(),this.y(),lineWrapper.otherShape.x(),lineWrapper.otherShape.y()]
+                lineWrapper.line.points(updatedPoints);
+            })
+        })
+    }
+
+    connect(node,draw = true){
+
+
+        if(!node.info.selectedPins.includes(this.info.name)){
+            console.log("vleze conn 2ds")
+            node.info.selectedPins.push(this.info.name);
+        }
+
+        if(!draw) return
+
+        const line = this.connLine.clone({
+            points: [this.x(),this.y(),node.x(),node.y()]
+        });
+
+        let lineWrapper = {
+            line: line,
+            otherShape: node
+        };
+
+        this.connectionLines.push(lineWrapper);
+
+        let lineWrapperSend = {
+            line: line,
+            otherShape: this
+        };
+
+        node.addLineReference(lineWrapperSend);
+
+        this.layer.add(lineWrapper.line);
+    }
+    
+    
+
+    addLineReference(line){
+        this.connectionLines.push(line);
+    }
+
+    removeLineWrapper(target){
+        this.connectionLines = this.connectionLines.filter(lineWrapper => lineWrapper.otherShape !== target);
+    }
+
+    removeConnection(shape){
+        this.info.selectedPins = this.info.selectedPins.filter(sl => sl !== shape.info.name)
+    }
+
+
+    removeConnectionLine(target){
+        this.connectionLines.forEach(lineWrapper => {
+            if (lineWrapper.otherShape === target){
+                lineWrapper.line.remove();
+                target.removeLineWrapper(this);
+                this.removeLineWrapper(target);
+            }
+        })
+    }
+
+
+    destroy() {
+        super.destroy();
+        this.connectionLines.forEach(lineWrapper => {
+            lineWrapper.line.remove()
+            lineWrapper.otherShape.removeLineWrapper(this);
+        });
+    }
+
+
+}
Index: imaps-frontend/src/scripts/base/MapShape.js
===================================================================
--- imaps-frontend/src/scripts/base/MapShape.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/base/MapShape.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,153 @@
+import Konva from "konva";
+
+export default class MapShape extends Konva.Shape {
+    constructor(config, layer, blockSize, snap) {
+        if (new.target === MapShape) {
+            throw new Error("Cannot instantiate abstract class BaseShape directly.");
+        }
+
+        console.log(config.x,"FFF");
+        super(config);
+        this.layer = layer;
+        this.blockSize = blockSize;
+        this._type = "";
+        this.snappable = snap;
+        this._info = {};
+        this.eventName = "";
+        this.infoText = null;
+        this.floorNum;
+
+        this.shadowForStrokeEnabled(false);
+        this.on("mouseover", () => (document.body.style.cursor = "pointer"));
+        this.on("mouseout", () => (document.body.style.cursor = "default"));
+        this.on("click", (e) => {
+            if(e.evt.altKey){
+                this.moveToTop();
+                this.getLayer()
+                    .find("Transformer")
+                    .forEach((t) => t.moveToTop());
+            }
+
+        });
+
+        if (snap) {
+            this.on("dragend", this.snapToGrid.bind(this));
+            this.on('dblclick', this.snapToGrid.bind(this));
+        }
+
+        this.on("transform", () => {
+            const scaleX = this.scaleX();
+            const scaleY = this.scaleY();
+            this.strokeWidth(1 / Math.max(scaleX, scaleY));
+        });
+
+
+        this.on('dragmove', () => {
+            if (this.infoText) {
+                this.updateTextPosition();
+            }
+        });
+
+    }
+
+    loadInfo(attrs) {
+        console.log("Abstract function");
+    }
+
+
+    initText() {
+        this.textOffsetX = 0;
+        this.textOffsetY = -30;
+        this.infoText = new Konva.Text({
+            x: this.x() + this.textOffsetX,
+            y: this.y() + this.textOffsetY,
+            text: this._info.name,
+            fontSize: 12,
+            fontFamily: 'Verdana',
+            fill: 'white',
+        });
+    }
+
+    updateTextPosition() {
+        if (this.infoText) {
+            this.infoText.x(this.x() + this.textOffsetX);
+            this.infoText.y(this.y() + this.textOffsetY);
+        }
+    }
+
+    displayName(layer) {
+        if (this.infoText) {
+            this.infoText.text(this._info.name);
+            layer.add(this.infoText);
+        }
+    }
+
+
+    destroy() {
+        super.destroy();
+        if (this.infoText !== null) {
+            this.infoText.remove()
+            console.log("cleared text")
+        }
+    }
+
+    setInfo(infoObj){
+        this.info = infoObj;
+    }
+
+    load(){
+        console.log("Abstract function")
+    }
+
+    _sceneFunc(context) {
+        let width = this.width();
+        let height = this.height();
+        context.beginPath();
+        context.rect(0, 0, width, height)
+        context.closePath();
+        context.fillStrokeShape(this);
+    }
+
+    clearText() {
+        if (this.infoText !== null) {
+            this.infoText.remove()
+            console.log("cleared text")
+        }
+
+    }
+
+    updateText(shapeName){
+            this.infoText.text = shapeName;
+            console.log("Updated text to : " + shapeName)
+    }
+
+    snapToGrid() {
+        this.position({
+            x: Math.round(this.x() / this.blockSize) * this.blockSize,
+            y: Math.round(this.y() / this.blockSize) * this.blockSize,
+        });
+
+    }
+
+    saveShapeDetails() {
+        console.log("This shape does not contain information");
+    }
+
+
+    get info() {
+        return this._info;
+    }
+
+    set info(formData) {
+        this._info = formData;
+    }
+
+    get type() {
+        return this._type;
+    }
+
+    set type(type) {
+        this._type = type
+    }
+
+}
Index: imaps-frontend/src/scripts/base/RenderedMapShape.js
===================================================================
--- imaps-frontend/src/scripts/base/RenderedMapShape.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/base/RenderedMapShape.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,89 @@
+import Konva from "konva";
+import config from "../net/netconfig.js";
+
+export default class RenderedMapShape extends Konva.Shape {
+  constructor(config) {
+    if (new.target === RenderedMapShape) {
+      throw new Error("Cannot instantiate abstract class RenderedMapShape directly.");
+    }
+
+    super(config);
+
+    this.info = {
+      name: "",
+      description: "",
+      type: "",
+    };
+    this.class = "Rect";
+    this.infoText = null;
+    this.textOffsetX = 0;
+    this.textOffsetY = 0;
+
+    this.eventName = "";
+
+  }
+
+  initText() {
+    const rectWidth = this.width();
+    const rectHeight = this.height();
+
+    this.infoText = new Konva.Text({
+      x: this.x(),
+      y: this.y(),
+      text: this.info.name || "no name",
+      fontSize: 10,
+      fontFamily: "Exo",
+      fill: "black",
+      align: "center",
+      verticalAlign: "middle",
+    });
+
+    this.infoText.offsetX(this.infoText.width() / 2);
+    this.infoText.offsetY(this.infoText.height() / 2);
+
+    this.infoText.x(this.x() + rectWidth / 2);
+    this.infoText.y(this.y() + rectHeight / 2);
+    this.infoText.rotation(this.rotation());
+  }
+
+
+  updateTextPosition() {
+    if (this.infoText) {
+      this.infoText.x(this.x() + this.textOffsetX);
+      this.infoText.y(this.y() + this.textOffsetY);
+    }
+  }
+
+  clearText() {
+    if (this.infoText !== null) {
+      this.infoText.remove()
+      console.log("cleared text")
+    }
+
+  }
+  _sceneFunc(context) {
+
+    let width = this.width();
+    let height = this.height();
+
+    const cornerRadius = this.attrs.cornerRadius;
+
+    context.beginPath();
+
+    if(!cornerRadius){
+      context.rect(0, 0, width, height)
+    } else {
+      Konva.Util.drawRoundedRectPath(context,width,height,cornerRadius)
+    }
+
+    context.closePath();
+    context.fillStrokeShape(this);
+  }
+
+
+  displayName(layer) {
+    if (this.infoText != null) {
+      layer.add(this.infoText);
+    }
+  }
+}
Index: imaps-frontend/src/scripts/main/MapBuilder.js
===================================================================
--- imaps-frontend/src/scripts/main/MapBuilder.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/main/MapBuilder.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -2,565 +2,657 @@
 import Konva from "konva";
 import HttpService from "../net/HttpService.js";
-import { zoomStage } from "../util/zoomStage.js";
+import {zoomStage} from "../util/zoomStage.js";
+import {addEventHandling} from "../util/addEventHandling.js";
+import MapNode from "../base/MapNode.js";
+import {json} from "react-router-dom";
+import log from "eslint-plugin-react/lib/util/log.js";
+import ShapeRegistry from "../util/ShapeRegistry.js";
+import shapeRegistry from "../util/ShapeRegistry.js";
+import triggerMapSave from "../util/triggerMapSave.js";
 
 export class MapBuilder {
-  constructor(containerId) {
-    this.container = document.getElementById(containerId);
-    this.stage = new Konva.Stage({
-      container: containerId,
-      width: this.container.clientWidth,
-      height: this.container.clientHeight,
-    });
-
-    // TODO AKO DRAGNIT NEKOJ OD POCETOK NA STAGE POZICIIVE KE SA ZEZNAT
-    // TODO jwt vo cookie
-    // TODO placed shape i mouseMoveHandler da ne callback ( da ne vrakjat funkcija)
-
-    this.gridLayer = new Konva.Layer();
-    this.mainLayer = new Konva.Layer();
-    this.dragLayer = new Konva.Layer();
-    this.infoPinLayer = new Konva.Layer();
-    this.textLayer = new Konva.Layer();
-    this.gridLayer.listening(false);
-
-    this.originalWidth = this.container.clientWidth;
-    this.originalHeight = this.container.clientHeight;
-
-    this.shapes = [];
-    this.blockSize = 10;
-    this.efficientDrawingMode = false;
-    this.roomTypes = [];
-
-    this.gridLine = new Konva.Line({
-      points: [],
-      stroke: "grey",
-      strokeWidth: 1,
-      opacity: 0.3,
-    });
-
-    this.gridLine.cache();
-
-    this.mainTransformer = new Konva.Transformer({
-      centeredScaling: false,
-      rotationSnaps: [0, 90, 180, 270],
-      anchorSize: 5,
-      padding: 2,
-      anchorFill: "#ef7539",
-      borderStroke: "black",
-      anchorStroke: "black",
-      cornerRadius: 20,
-      anchorCornerRadius: 10,
-      anchorDragBoundFunc: this.transformerSnapFunc(),
-    });
-
-    this.selectionRectangle = new Konva.Rect({
-      fill: "rgba(200,0,255,0.5)",
-      visible: false,
-      listening: false,
-      zIndex: 100,
-    });
-
-    this.x1 = 0;
-    this.y1 = 0;
-    this.x2 = 0;
-    this.y2 = 0;
-
-    this.selecting = false;
-
-    this.initialize();
-  }
-
-  initialize() {
-    this.drawGrid();
-    this.mainLayer.add(this.mainTransformer);
-    this.mainLayer.add(this.selectionRectangle);
-    this.stage.add(this.gridLayer);
-    this.stage.add(this.dragLayer);
-    this.stage.add(this.mainLayer);
-    this.stage.add(this.infoPinLayer);
-    this.stage.add(this.textLayer);
-    this.setupEventListeners();
-  }
-
-  setupEventListeners() {
-    document.getElementById("shapeOptions").addEventListener("click", this.selectShape.bind(this));
-    document.getElementById("render-button").addEventListener("click", this.render.bind(this));
-    window.addEventListener("keydown", this.handleExitSelection.bind(this));
-    window.addEventListener("keydown", this.handleDelete.bind(this));
-    window.addEventListener("keydown", this.rotateShapesBy90Deg.bind(this));
-    window.addEventListener("keydown", this.toggleEfficientDrawingMode.bind(this));
-    window.addEventListener("resize", this.handleResize.bind(this));
-    this.stage.on("mousedown touchstart", this.handleMouseDown.bind(this));
-    this.stage.on("mousemove touchmove", this.handleMouseMove.bind(this));
-    this.stage.on("mouseup touchend", this.handleMouseUp.bind(this));
-    this.stage.on("click tap", this.handleStageClick.bind(this));
-    this.stage.on("contextmenu", this.placeInfoPin.bind(this));
-    this.stage.on("dragmove", this.dragStage.bind(this));
-    this.stage.on("wheel", this.zoom.bind(this));
-  }
-
-  detachKeyPressEventListeners() {
-    window.removeEventListener("keydown", this.handleExitSelection.bind(this));
-    window.removeEventListener("keydown", this.handleDelete.bind(this));
-    window.removeEventListener("keydown", this.rotateShapesBy90Deg.bind(this));
-    window.removeEventListener("keydown", this.toggleEfficientDrawingMode.bind(this));
-  }
-  attachKeyPressEventListeners() {
-    window.addEventListener("keydown", this.handleExitSelection.bind(this));
-    window.addEventListener("keydown", this.handleDelete.bind(this));
-    window.addEventListener("keydown", this.rotateShapesBy90Deg.bind(this));
-    window.addEventListener("keydown", this.toggleEfficientDrawingMode.bind(this));
-  }
-
-  dragStage(e) {
-    if (!e.evt.shiftKey) return;
-    this.drawGrid();
-  }
-
-  transformerSnapFunc() {
-    return (oldPos, newPos) => {
-      const snapDistance = 8;
-
-      if (this.mainTransformer.getActiveAnchor() === "rotater") {
-        return newPos;
-      }
-
-      const distance = Math.sqrt(Math.pow(newPos.x - oldPos.x, 2) + Math.pow(newPos.y - oldPos.y, 2));
-
-      if (distance > snapDistance) {
-        return newPos;
-      }
-
-      const nextX = Math.round(newPos.x / this.blockSize) * this.blockSize;
-      const diffX = Math.abs(newPos.x - nextX);
-
-      const nextY = Math.round(newPos.y / this.blockSize) * this.blockSize;
-      const diffY = Math.abs(newPos.y - nextY);
-
-      const snapToX = diffX < snapDistance;
-      const snapToY = diffY < snapDistance;
-
-      if (snapToX && !snapToY) {
+    constructor(containerId,floorNum,mapName) {
+        this.container = document.getElementById(containerId);
+        this.stage = new Konva.Stage({
+            container: containerId,
+            width: this.container.clientWidth,
+            height: this.container.clientHeight,
+        });
+
+        // TODO AKO DRAGNIT NEKOJ OD POCETOK NA STAGE POZICIIVE KE SA ZEZNAT
+        // TODO jwt vo cookie
+        // TODO placed shape i mouseMoveHandler da ne callback ( da ne vrakjat funkcija)
+        // TODO text na top layer sekogas
+
+        this._floorNum = floorNum;
+        this.mapName = mapName;
+
+        this.gridLayer = new Konva.Layer();
+        this.mainLayer = new Konva.Layer();
+        this.dragLayer = new Konva.Layer();
+        this.infoPinLayer = new Konva.Layer();
+        this.prioLayer = new Konva.Layer();
+        this.textLayer = new Konva.Layer();
+        this.gridLayer.listening(false);
+
+
+        this.othStairs = [];
+
+        this.blockSize = 10;
+        this.efficientDrawingMode = false;
+        this.roomTypes = [];
+
+        this.gridLine = new Konva.Line({
+            points: [],
+            stroke: "grey",
+            strokeWidth: 1,
+            opacity: 0.3,
+        });
+
+        this.gridLine.cache();
+
+        this.mainTransformer = new Konva.Transformer({
+            centeredScaling: false,
+            rotationSnaps: [0, 90, 180, 270],
+            anchorSize: 5,
+            padding: 2,
+            anchorFill: "#f6031f",
+            borderStroke: "black",
+            anchorStroke: "black",
+            cornerRadius: 20,
+            anchorCornerRadius: 10,
+            anchorDragBoundFunc: this.transformerSnapFunc(),
+        });
+
+        this.selectionRectangle = new Konva.Rect({
+            fill: "rgba(56,194,245,0.5)",
+            visible: false,
+            listening: false,
+            zIndex: 100,
+        });
+
+        this.x1 = 0;
+        this.y1 = 0;
+        this.x2 = 0;
+        this.y2 = 0;
+
+        this.selecting = false;
+
+        this.initialize();
+    }
+
+    initialize() {
+        this.drawGrid();
+        this.mainLayer.add(this.mainTransformer);
+        this.mainLayer.add(this.selectionRectangle);
+        this.stage.add(this.gridLayer);
+        this.stage.add(this.dragLayer);
+        this.stage.add(this.mainLayer);
+        this.stage.add(this.infoPinLayer);
+        this.stage.add(this.textLayer);
+        this.setupEventListeners();
+    }
+
+    setupEventListeners() {
+        document.getElementById("shapeOptions").addEventListener("click", this.selectShape.bind(this));
+        window.addEventListener("keydown", this.handleExitSelection.bind(this));
+        window.addEventListener("keydown", this.handleDelete.bind(this));
+        window.addEventListener("keydown", this.rotateShapesBy90Deg.bind(this));
+        window.addEventListener("keydown", this.toggleEfficientDrawingMode.bind(this));
+        window.addEventListener("resize", this.handleResize.bind(this));
+
+        this.boundEscapeEventListener = this.handleExitSelection.bind(this);
+        this.boundDeleteEventListener = this.handleDelete.bind(this);
+        this.boundRotateShapeEventListener = this.rotateShapesBy90Deg.bind(this)
+        this.boundEfficientDrawingModeEventListener = this.toggleEfficientDrawingMode.bind(this);
+
+        //this.attachKeyPressEventListeners();
+
+        this.stage.on("mousedown touchstart", this.handleMouseDown.bind(this));
+        this.stage.on("mousemove touchmove", this.handleMouseMove.bind(this));
+        this.stage.on("mouseup touchend", this.handleMouseUp.bind(this));
+        this.stage.on("click tap", this.handleStageClick.bind(this));
+        this.stage.on("contextmenu", this.placeInfoPin.bind(this));
+        this.stage.on("dragmove", this.dragStage.bind(this));
+        this.stage.on("wheel", this.zoom.bind(this));
+    }
+
+    detachKeyPressEventListeners() {
+        window.removeEventListener("keydown", this.boundEscapeEventListener);
+        window.removeEventListener("keydown", this.boundDeleteEventListener);
+        window.removeEventListener("keydown", this.boundRotateShapeEventListener);
+        window.removeEventListener("keydown", this.boundEfficientDrawingModeEventListener);
+    }
+
+    attachKeyPressEventListeners() {
+        window.addEventListener("keydown", this.boundEscapeEventListener);
+        window.addEventListener("keydown", this.boundDeleteEventListener);
+        window.addEventListener("keydown", this.boundRotateShapeEventListener);
+        window.addEventListener("keydown", this.boundEfficientDrawingModeEventListener);
+    }
+
+    dragStage(e) {
+        if (!e.evt.shiftKey) return;
+        this.drawGrid();
+    }
+
+    transformerSnapFunc() {
+        return (oldPos, newPos) => {
+            const snapDistance = 8;
+
+            if (this.mainTransformer.getActiveAnchor() === "rotater") {
+                return newPos;
+            }
+
+            const distance = Math.sqrt(Math.pow(newPos.x - oldPos.x, 2) + Math.pow(newPos.y - oldPos.y, 2));
+
+            if (distance > snapDistance) {
+                return newPos;
+            }
+
+            const nextX = Math.round(newPos.x / this.blockSize) * this.blockSize;
+            const diffX = Math.abs(newPos.x - nextX);
+
+            const nextY = Math.round(newPos.y / this.blockSize) * this.blockSize;
+            const diffY = Math.abs(newPos.y - nextY);
+
+            const snapToX = diffX < snapDistance;
+            const snapToY = diffY < snapDistance;
+
+            if (snapToX && !snapToY) {
+                return {
+                    x: nextX,
+                    y: oldPos.y,
+                };
+            } else if (!snapToX && snapToY) {
+                return {
+                    x: oldPos.x,
+                    y: nextY,
+                };
+            } else if (snapToX && snapToY) {
+                return {
+                    x: nextX,
+                    y: nextY,
+                };
+            }
+
+            return newPos;
+        };
+    }
+
+    handleResize() {
+        this.stage.width(this.container.offsetWidth);
+        this.stage.height(this.container.offsetHeight);
+        this.drawGrid();
+    }
+
+    zoom(e) {
+        zoomStage(e, this.stage, true);
+        this.drawGrid();
+    }
+
+    get floorNum(){
+        return this._floorNum;
+    }
+
+    set floorNum(val){
+        this._floorNum = val;
+    }
+
+    drawGrid() {
+        this.gridLayer.destroyChildren();
+
+        let width = this.stage.width();
+        let height = this.stage.height();
+
+        //presmetka od globalen koordinaten sistem vo lokalen na canvasot
+        let transform = this.stage.getAbsoluteTransform().copy().invert();
+        let topLeft = transform.point({
+            x: 0,
+            y: 0,
+        });
+
+        let bottomRight = transform.point({
+            x: width,
+            y: height,
+        });
+
+        let startX = Math.floor(topLeft.x / this.blockSize) * this.blockSize;
+        let startY = Math.floor(topLeft.y / this.blockSize) * this.blockSize;
+
+        let endX = Math.ceil(bottomRight.x / this.blockSize) * this.blockSize;
+        let endY = Math.ceil(bottomRight.y / this.blockSize) * this.blockSize;
+
+        for (let x = startX; x <= endX; x += this.blockSize) {
+            let line = this.gridLine.clone({
+                points: [x + 0.5, topLeft.y - this.blockSize, x + 0.5, bottomRight.y + this.blockSize],
+            });
+
+            line.transformsEnabled("position");
+            line.perfectDrawEnabled(false);
+            line.shadowForStrokeEnabled(false);
+
+            this.gridLayer.add(line);
+        }
+
+        for (let y = startY; y <= endY; y += this.blockSize) {
+            let line = this.gridLine.clone({
+                points: [topLeft.x - this.blockSize, y + 0.5, bottomRight.x + this.blockSize, y + 0.5],
+            });
+
+            line.perfectDrawEnabled(false);
+            line.shadowForStrokeEnabled(false);
+            line.transformsEnabled("position");
+            this.gridLayer.add(line);
+        }
+
+        this.mainLayer.moveToTop();
+        this.infoPinLayer.moveToTop();
+
+        this.gridLayer.batchDraw();
+    }
+
+    placeInfoPin(e) {
+        e.evt.preventDefault();
+        let mousePos = this.stage.getRelativePointerPosition();
+        const attrs = {
+            type: "InfoPin",
+            position: mousePos,
+            blockSize: this.blockSize,
+            layer: this.mainLayer,
+            rotation: 0,
+            scaleX: 1,
+            scaleY: 1,
+            increment: true,
+            floorNum: this.floorNum
+        };
+        let infoPin = Factory.createShape("InfoPin", attrs);
+        addEventHandling(infoPin, this, "dblclick");
+        //this.shapes.push(infoPin);
+        ShapeRegistry.add(infoPin)
+        this.mainLayer.add(infoPin);
+        infoPin.displayName(this.textLayer);
+        triggerMapSave()
+
+        console.log(infoPin.name());
+    }
+
+    toggleEfficientDrawingMode(e) {
+        if (e.key === "e" || e.key === "E") {
+            this.efficientDrawingMode = !this.efficientDrawingMode;
+            console.log("EFFICIENT DRAWING MODE is: ", this.efficientDrawingMode);
+
+            if (!this.efficientDrawingMode) {
+                this.stopDrawing();
+            }
+        }
+    }
+
+    placeShape() {
+        const mousePos = this.stage.getRelativePointerPosition();
+        const attrs = {
+            position: mousePos,
+            width: this.blockSize,
+            height: this.blockSize,
+            layer: this.mainLayer,
+            rotation: this.hoverObj.rotation(),
+            scaleX: 1,
+            scaleY: 1,
+            increment: true,
+            snap: true,
+            fromLoad: false,
+            blockSize: this.blockSize,
+            floorNum: this.floorNum
+        };
+
+        const placedObj = Factory.createShape(this.hoverObj.type, attrs);
+        if (!placedObj) return;
+
+        console.info("ATTRS FNUM",attrs.floorNum)
+
+        this.mainLayer.add(placedObj);
+        //this.shapes.push(placedObj);
+        console.log("VO PLACED SHAEPS WALL ZITI SE: " + placedObj.className);
+        ShapeRegistry.add(placedObj);
+        addEventHandling(placedObj, this, "dblclick");
+        this.mainLayer.draw();
+
+        // site ovie func da se vo edna funkcija vo shape.
+
+        placedObj.displayName(this.textLayer);
+        placedObj.snapToGrid();
+
+        triggerMapSave();
+
+        if (!this.efficientDrawingMode) {
+            this.stopDrawing();
+        }
+    }
+
+    stopDrawing() {
+        this.mainTransformer.nodes([]);
+        if (this.hoverObj != null) this.hoverObj.remove();
+        this.dragLayer.removeChildren();
+        this.stage.off("mousemove", this.boundMouseMoveHandler);
+        this.stage.off("click", this.boundPlaceShapeHandler);
+    }
+
+    mouseMoveHandler() {
+        const mousePos = this.stage.getRelativePointerPosition();
+        this.hoverObj.position({x: mousePos.x, y: mousePos.y});
+        this.hoverObj.visible(true);
+    }
+
+    startDrawing(shapeType) {
+        const attrs = {
+            position: {x: 0, y: 0},
+            width: this.blockSize,
+            height: this.blockSize,
+            layer: this.mainLayer,
+            rotation: 0,
+            scaleX: 1,
+            scaleY: 1,
+            increment: false,
+            snap: true,
+            fromLoad: false,
+            blockSize: this.blockSize
+        };
+        this.hoverObj = Factory.createShape(shapeType, attrs);
+
+        console.log("HOVBER OBK:", this.hoverObj)
+
+        this.hoverObj.visible(false);
+        this.dragLayer.add(this.hoverObj);
+        this.dragLayer.moveToTop();
+        this.boundMouseMoveHandler = this.mouseMoveHandler.bind(this);
+        this.boundPlaceShapeHandler = this.placeShape.bind(this);
+
+        this.stage.on("mousemove", this.boundMouseMoveHandler);
+        this.stage.on("click", this.boundPlaceShapeHandler);
+    }
+
+    selectShape(e) {
+        if (e.target.tagName === "LI") {
+            const shapeType = e.target.getAttribute("data-info");
+            this.startDrawing(shapeType);
+            this.mainTransformer.nodes([]);
+        }
+    }
+
+    rotateShapesBy90Deg(e) {
+        if (e.key === "r" || e.key === "R") {
+            if (this.hoverObj) {
+                this.hoverObj.rotate(90);
+            }
+            this.mainTransformer.nodes().forEach((node) => {
+                node.rotate(90);
+            });
+        }
+    }
+
+    handleDelete(e) {
+        if (e.key === "Delete") {
+            this.mainTransformer.nodes().forEach((node) => {
+                node.remove();
+                node.destroy();
+                ShapeRegistry.delete(node);
+                triggerMapSave();
+            });
+            this.mainTransformer.nodes([]);
+            this.mainLayer.batchDraw();
+        }
+    }
+
+    handleExitSelection(e) {
+        if (e.key === "Escape") {
+            this.mainTransformer.nodes([]);
+            this.stopDrawing();
+        }
+    }
+
+    handleMouseDown(e) {
+        this.stage.draggable(e.evt.shiftKey);
+
+        if (e.target !== this.stage) {
+            return;
+        }
+
+        e.evt.preventDefault();
+        this.x1 = this.stage.getRelativePointerPosition().x;
+        this.y1 = this.stage.getRelativePointerPosition().y;
+        this.x2 = this.stage.getRelativePointerPosition().x;
+        this.y2 = this.stage.getRelativePointerPosition().y;
+
+        this.selectionRectangle.width(0);
+        this.selectionRectangle.height(0);
+        this.selecting = true;
+    }
+
+    handleMouseMove(e) {
+        if (!this.selecting) {
+            return;
+        }
+        e.evt.preventDefault();
+        this.x2 = this.stage.getRelativePointerPosition().x;
+        this.y2 = this.stage.getRelativePointerPosition().y;
+
+        this.selectionRectangle.setAttrs({
+            visible: true,
+            x: Math.min(this.x1, this.x2),
+            y: Math.min(this.y1, this.y2),
+            width: Math.abs(this.x2 - this.x1),
+            height: Math.abs(this.y2 - this.y1),
+        });
+    }
+
+    handleMouseUp(e) {
+        this.selecting = false;
+        this.stage.draggable(false);
+
+        if (!this.selectionRectangle.visible()) {
+            return;
+        }
+
+        e.evt.preventDefault();
+        this.selectionRectangle.visible(false);
+        const shapes = this.stage.find(".mapObj");
+        const box = this.selectionRectangle.getClientRect();
+        const selected = shapes.filter((shape) => Konva.Util.haveIntersection(box, shape.getClientRect()));
+        this.mainTransformer.nodes(selected);
+        console.log(this.mainTransformer.nodes());
+    }
+
+    saveShapeDetails() {
+        // this.shapes.forEach(shape => {
+        //     shape.saveShapeDetails();
+        //     console.log(shape.info);
+        // });
+        ShapeRegistry.saveDetails();
+        console.log("thisflornum",this.floorNum)
+        return  {
+            shapes: ShapeRegistry.getShapes(this.floorNum),
+            roomTypes: JSON.stringify(this.roomTypes),
+            mapName: this.mapName,
+            floorNum: this.floorNum
+        }
+    }
+
+    getPayload(){
+        this.saveShapeDetails();
         return {
-          x: nextX,
-          y: oldPos.y,
-        };
-      } else if (!snapToX && snapToY) {
-        return {
-          x: oldPos.x,
-          y: nextY,
-        };
-      } else if (snapToX && snapToY) {
-        return {
-          x: nextX,
-          y: nextY,
-        };
-      }
-
-      return newPos;
-    };
-  }
-
-  handleResize() {
-    this.stage.width(this.container.offsetWidth);
-    this.stage.height(this.container.offsetHeight);
-    this.drawGrid();
-  }
-
-  zoom(e) {
-   zoomStage(e,this.stage);
-   this.drawGrid();
-  }
-
-  drawGrid() {
-    this.gridLayer.destroyChildren();
-
-    let width = this.stage.width();
-    let height = this.stage.height();
-
-    //presmetka od globalen koordinaten sistem vo lokalen na canvasot
-    let transform = this.stage.getAbsoluteTransform().copy().invert();
-    let topLeft = transform.point({
-      x: 0,
-      y: 0,
-    });
-
-    let bottomRight = transform.point({
-      x: width,
-      y: height,
-    });
-
-    let startX = Math.floor(topLeft.x / this.blockSize) * this.blockSize;
-    let startY = Math.floor(topLeft.y / this.blockSize) * this.blockSize;
-
-    let endX = Math.ceil(bottomRight.x / this.blockSize) * this.blockSize;
-    let endY = Math.ceil(bottomRight.y / this.blockSize) * this.blockSize;
-
-    for (let x = startX; x <= endX; x += this.blockSize) {
-      let line = this.gridLine.clone({
-        points: [x + 0.5, topLeft.y - this.blockSize, x + 0.5, bottomRight.y + this.blockSize],
-      });
-
-      line.transformsEnabled("position");
-      line.perfectDrawEnabled(false);
-      line.shadowForStrokeEnabled(false);
-
-      this.gridLayer.add(line);
-    }
-
-    for (let y = startY; y <= endY; y += this.blockSize) {
-      let line = this.gridLine.clone({
-        points: [topLeft.x - this.blockSize, y + 0.5, bottomRight.x + this.blockSize, y + 0.5],
-      });
-
-      line.perfectDrawEnabled(false);
-      line.shadowForStrokeEnabled(false);
-      line.transformsEnabled("position");
-      this.gridLayer.add(line);
-    }
-
-    this.mainLayer.moveToTop();
-    this.infoPinLayer.moveToTop();
-
-    this.gridLayer.batchDraw();
-  }
-
-  placeInfoPin(e) {
-    e.evt.preventDefault();
-    let mousePos = this.stage.getRelativePointerPosition();
-    let infoPin = Factory.createShape("InfoPin", mousePos, this.blockSize, this.mainLayer, 0,1,1,true);
-    this.addModalHandling(infoPin);
-    this.shapes.push(infoPin);
-    this.mainLayer.add(infoPin)
-    infoPin.displayName(this.textLayer);
-    console.log(infoPin.name());
-  }
-
-  toggleEfficientDrawingMode(e) {
-    if (e.key === "e" || e.key === "E") {
-      this.efficientDrawingMode = !this.efficientDrawingMode;
-      console.log("EFFICIENT DRAWING MODE is: ", this.efficientDrawingMode);
-
-      if (!this.efficientDrawingMode) {
-        this.stopDrawing();
-      }
-    }
-  }
-
-  placeShape() {
-    const mousePos = this.stage.getRelativePointerPosition();
-    const placedObj = Factory.createShape(
-      this.hoverObj.type,
-      mousePos,
-      this.blockSize,
-      this.mainLayer,
-      this.hoverObj.rotation(),
-        1,
-        1,
-        true
-    );
-
-    if (!placedObj) return;
-
-    this.mainLayer.add(placedObj);
-    this.shapes.push(placedObj);
-    this.addModalHandling(placedObj);
-    this.mainLayer.draw();
-    placedObj.displayName(this.textLayer);
-    placedObj.snapToGrid();
-
-    if (!this.efficientDrawingMode) {
-      this.stopDrawing();
-    }
-  }
-
-  stopDrawing() {
-    this.mainTransformer.nodes([]);
-    this.hoverObj.remove();
-    this.dragLayer.removeChildren();
-    this.stage.off("mousemove", this.boundMouseMoveHandler);
-    this.stage.off("click", this.boundPlaceShapeHandler);
-  }
-
-  mouseMoveHandler() {
-    const mousePos = this.stage.getRelativePointerPosition();
-    this.hoverObj.position({ x: mousePos.x, y: mousePos.y });
-    this.hoverObj.visible(true);
-  }
-
-  startDrawing(shapeType) {
-    let pos = { x: 0, y: 0 };
-    this.hoverObj = Factory.createShape(shapeType, pos, this.blockSize, this.dragLayer, 0);
-
-    this.hoverObj.visible(false);
-    this.dragLayer.add(this.hoverObj);
-    this.dragLayer.moveToTop();
-    this.boundMouseMoveHandler = this.mouseMoveHandler.bind(this);
-    this.boundPlaceShapeHandler = this.placeShape.bind(this);
-
-    this.stage.on("mousemove", this.boundMouseMoveHandler);
-    this.stage.on("click", this.boundPlaceShapeHandler);
-  }
-
-  selectShape(e) {
-    if (e.target.tagName === "LI") {
-      const shapeType = e.target.getAttribute("data-info");
-      this.startDrawing(shapeType);
-      this.mainTransformer.nodes([]);
-    }
-  }
-
-  addModalHandling(shape) {
-    shape.on("dblclick", () => {
-      const eventName = shape.modalEventName;
-      if (eventName) {
-        const data = {
-          room: shape,
-          map: this,
-        };
-        const event = new CustomEvent(eventName, { detail: data });
-        window.dispatchEvent(event);
-      }
-    });
-  }
-
-  rotateShapesBy90Deg(e) {
-    if (e.key === "r" || e.key === "R") {
-      if (this.hoverObj) {
-        this.hoverObj.rotate(90);
-      }
-      this.mainTransformer.nodes().forEach((node) => {
-        node.rotate(90);
-      });
-    }
-  }
-
-  handleDelete(e) {
-    if (e.key === "Delete") {
-      this.mainTransformer.nodes().forEach((node) => {
-        node.remove();
-        this.shapes.splice(this.shapes.indexOf(node), 1);
-      });
-      this.mainTransformer.nodes([]);
-      this.mainLayer.batchDraw();
-    }
-  }
-
-  handleExitSelection(e) {
-    if (e.key === "Escape") {
-      this.mainTransformer.nodes([]);
-      this.stopDrawing();
-    }
-  }
-
-  handleMouseDown(e) {
-    this.stage.draggable(e.evt.shiftKey);
-
-    if (e.target !== this.stage) {
-      return;
-    }
-
-    e.evt.preventDefault();
-    this.x1 = this.stage.getRelativePointerPosition().x;
-    this.y1 = this.stage.getRelativePointerPosition().y;
-    this.x2 = this.stage.getRelativePointerPosition().x;
-    this.y2 = this.stage.getRelativePointerPosition().y;
-
-    this.selectionRectangle.width(0);
-    this.selectionRectangle.height(0);
-    this.selecting = true;
-  }
-
-  handleMouseMove(e) {
-    if (!this.selecting) {
-      return;
-    }
-    e.evt.preventDefault();
-    this.x2 = this.stage.getRelativePointerPosition().x;
-    this.y2 = this.stage.getRelativePointerPosition().y;
-
-    this.selectionRectangle.setAttrs({
-      visible: true,
-      x: Math.min(this.x1, this.x2),
-      y: Math.min(this.y1, this.y2),
-      width: Math.abs(this.x2 - this.x1),
-      height: Math.abs(this.y2 - this.y1),
-    });
-  }
-
-  handleMouseUp(e) {
-    this.selecting = false;
-    this.stage.draggable(false);
-
-    if (!this.selectionRectangle.visible()) {
-      return;
-    }
-
-    e.evt.preventDefault();
-    this.selectionRectangle.visible(false);
-    const shapes = this.stage.find(".mapObj");
-    const box = this.selectionRectangle.getClientRect();
-    const selected = shapes.filter((shape) => Konva.Util.haveIntersection(box, shape.getClientRect()));
-    this.mainTransformer.nodes(selected);
-    console.log(this.mainTransformer.nodes());
-  }
-
-  saveShapeDetails() {
-    this.shapes.forEach((room) => {
-      room.saveShapeDetails();
-      console.log(room.info);
-    });
-  }
-
-  async render() {
-    this.saveShapeDetails();
-    const httpService = new HttpService("http://localhost:8080/api/protected", true);
-    try {
-      const response = await httpService.post("/render", this.shapes);
-      console.log(response);
-    } catch (err) {
-      console.log("ERROR --> Could not render map --->", err);
-    }
-  }
-
-  async saveMap(mapName) {
-    this.saveShapeDetails();
-    const httpService = new HttpService("http://localhost:8080/api/protected/maps", true);
-    try {
-      const response = await httpService.put(`/save?mapName=${mapName}`, this.shapes);
-      console.log(response, "resp in builder");
-    } catch (err) {
-      console.log("ERROR --> Could not Save map --->", err);
-    }
-  }
-
-  handleStageClick(e) {
-    if (this.selectionRectangle.visible()) {
-      return;
-    }
-
-    if (e.target === this.stage) {
-      this.mainTransformer.nodes([]);
-      return;
-    }
-
-    if (!e.target.hasName("mapObj")) {
-      return;
-    }
-
-    const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
-    const isSelected = this.mainTransformer.nodes().indexOf(e.target) >= 0;
-
-    if (!metaPressed && !isSelected) {
-      this.mainTransformer.nodes([e.target]);
-      console.log("Sel 1");
-    } else if (metaPressed && isSelected) {
-      const nodes = this.mainTransformer.nodes().slice();
-      nodes.splice(nodes.indexOf(e.target), 1);
-      this.mainTransformer.nodes(nodes);
-    } else if (metaPressed && !isSelected) {
-      const nodes = this.mainTransformer.nodes().concat([e.target]);
-      this.mainTransformer.nodes(nodes);
-    }
-  }
-
-  addRoomType(roomType) {
-    this.roomTypes.push(roomType);
-  }
-
-  getRoomTypes() {
-    return this.roomTypes;
-  }
-
-  getRooms() {
-    return this.getShapeInfoByType("Room");
-  }
-
-  getPins() {
-    return this.getShapeInfoByType("InfoPin");
-  }
-
-  getEntrances() {
-    return this.getShapeInfoByType("Entrance");
-  }
-
-  getConnections() {
-    const pins = this.getShapeInfoByType("InfoPin");
-    const entrances = this.getShapeInfoByType("Entrance");
-    return [...pins, ...entrances];
-  }
-
-  getShapeInfoByType(type) {
-    return this.shapes.filter((shape) => shape.className === type).map((shape) => shape.info);
-  }
-
-  updateConnections() {
-    console.log("Update");
-
-    this.shapes.forEach((shape) => {
-      if (shape.className === "InfoPin" || shape.className === "Entrance") {
-        shape.info.selectedPins.forEach((connectedShapeName) => {
-          const connectedShape = this.shapes.find((s) => s.info.name === connectedShapeName);
-          if (
-            connectedShape &&
-            (connectedShape.className === "InfoPin" || connectedShape.className === "Entrance")
-          ) {
-            if (!connectedShape.info.selectedPins.includes(shape.info.name)) {
-              connectedShape.info.selectedPins.push(shape.info.name);
-            }
-          }
-        });
-      }
-    });
-  }
-
-  removeConnection(from, to) {
-    this.shapes
-      .filter((s) => s.info.name === from || s.info.name === to)
-      .forEach((s) => {
-        s.info.selectedPins = s.info.selectedPins.filter((pin) => pin !== from && pin !== to);
-      });
-    console.log("Remove");
-  }
-
-  updateRoomNames() {
-    this.textLayer.removeChildren();
-    this.shapes.forEach((shape) => {
-      shape.displayName(this.textLayer);
-    });
-    this.textLayer.children.forEach((child) => console.log(child));
-  }
-
-  clearMap() {
-    this.mainLayer.removeChildren();
-    this.shapes = [];
-    this.hoverObj = null;
-  }
-
-  deserializeMap(data) {
-    console.log("DESERIALIZING: ", data);
-    this.clearMap();
-    let dsrData = JSON.parse(data);
-    dsrData.forEach((child) => {
-      const shape = JSON.parse(child);
-      const loadedShape = Factory.createShape(
-        shape.className,
-        { x: shape.attrs.x, y: shape.attrs.y },
-        this.blockSize,
-        this.mainLayer,
-        shape.attrs.rotation,
-          shape.attrs.scaleX,
-          shape.attrs.scaleY
-      );
-      loadedShape.loadInfo(shape.attrs);
-      this.shapes.push(loadedShape);
-      this.addModalHandling(loadedShape);
-      this.mainLayer.add(loadedShape);
-    });
-    this.mainTransformer.nodes([]);
-    this.mainLayer.add(this.mainTransformer);
-    this.mainLayer.add(this.selectionRectangle);
-
-    this.shapes.forEach((shape) => shape.displayName(this.textLayer));
-  }
+            shapes: ShapeRegistry.getShapes(this.floorNum),
+            roomTypes: JSON.stringify(this.roomTypes),
+            mapName: this.mapName,
+            floorNum: this.floorNum
+        }
+    }
+
+
+    handleStageClick(e) {
+        if (this.selectionRectangle.visible()) {
+            return;
+        }
+
+        if (e.target === this.stage) {
+            this.mainTransformer.nodes([]);
+            return;
+        }
+
+        if (!e.target.hasName("mapObj")) {
+            return;
+        }
+
+        const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
+        const isSelected = this.mainTransformer.nodes().indexOf(e.target) >= 0;
+
+        if (!metaPressed && !isSelected) {
+            this.mainTransformer.nodes([e.target]);
+            console.log("Sel 1");
+        } else if (metaPressed && isSelected) {
+            const nodes = this.mainTransformer.nodes().slice();
+            nodes.splice(nodes.indexOf(e.target), 1);
+            this.mainTransformer.nodes(nodes);
+        } else if (metaPressed && !isSelected) {
+            const nodes = this.mainTransformer.nodes().concat([e.target]);
+            this.mainTransformer.nodes(nodes);
+        }
+    }
+
+    addRoomType(type) {
+        this.roomTypes.push(type);
+    }
+
+    removeRoomType(targetType) {
+        this.roomTypes = this.roomTypes.filter(type => type !== targetType);
+    }
+
+    getRoomTypes() {
+        return this.roomTypes;
+    }
+
+    getRooms() {
+        return this.getShapeInfoByType("Room");
+    }
+
+    getPins() {
+        return this.getShapeInfoByType("InfoPin");
+    }
+
+    getEntrances() {
+        return this.getShapeInfoByType("Entrance");
+    }
+
+
+
+    getShapeInfoByType(type) {
+        return ShapeRegistry.getShapes(this.floorNum).filter((shape) => shape.className === type).map((shape) => shape.info);
+    }
+
+
+    drawConnection(node1Name, node2Name) {
+
+        ShapeRegistry.drawConnection(node1Name,node2Name);
+    }
+
+    getNodeByName(name) {
+        return ShapeRegistry.getShapes(this.floorNum).filter(shape => shape instanceof MapNode && shape.info.name === name)[0];
+    }
+
+    removeConnection(from, to) {
+        ShapeRegistry.removeConnection(from,to);
+    }
+
+    updateRoomNames() {
+        this.textLayer.removeChildren();
+        ShapeRegistry.getShapes(this.floorNum).forEach((shape) => {
+            shape.displayName(this.textLayer);
+        });
+
+    }
+
+    isMainEntranceSelected() {
+        console.log(this.getEntrances().forEach((en) => console.log(en.isMainEntrance, "asdsad")));
+
+        let hasMainEntrance = false;
+
+        this.getEntrances().forEach((entrance) => {
+            if (entrance.isMainEntrance === true) hasMainEntrance = true;
+        });
+
+        return hasMainEntrance;
+
+    }
+
+    clearMap() {
+        this.mainLayer.removeChildren();
+        this.hoverObj = null;
+    }
+
+
+    // ova  klasa i map display da nasledbat od glavna klasa
+
+    loadNewFloor(floor) {
+
+        this._floorNum = floor?.num;
+        let data = floor?.mapData;
+
+        if (data == null || data === "") return;
+
+        this.deserializeMap(data);
+        shapeRegistry.getShapes(this.floorNum).forEach((shape) => {
+            this.mainLayer.add(shape);
+        });
+
+
+    }
+
+    //nov
+    deserializeMap(data) {
+        console.log("DESERIALIZING: ", data);
+        ShapeRegistry.clear(this.floorNum);
+
+        if (data != null) {
+            const dsrData = JSON.parse(data);
+            //load shapes
+            dsrData.forEach((shape) => {
+                const attrs = {
+                    position: {x: shape.attrs.x, y: shape.attrs.y},
+                    width: shape.attrs.width,
+                    height: shape.attrs.height,
+                    layer: this.mainLayer,
+                    blockSize: this.blockSize,
+                    rotation: shape.attrs.rotation,
+                    scaleX: shape.attrs.scaleX,
+                    scaleY: shape.attrs.scaleY,
+                    increment: false,
+                    snap: true,
+                    fromLoad: true,
+                    floorNum: this.floorNum
+                };
+
+                const loadedShape = Factory.createShape(shape.className, attrs);
+                loadedShape.loadInfo(shape.attrs);
+                ShapeRegistry.add(loadedShape);
+                // na destroy trebit events da sa trgnat
+                addEventHandling(loadedShape, this, "dblclick");
+            });
+            let nodes = ShapeRegistry.getShapes(this.floorNum).filter((shape) => shape.className === "InfoPin" || shape.className === "Entrance" || shape.className === "Stairs");
+            nodes.forEach((pin) => {
+                let connectedPins = pin.info.selectedPins;
+                if (connectedPins) {
+                    connectedPins.forEach((slPin) => {
+                        console.log("CONN node1: " + pin + "conn node2: " + slPin)
+                        this.drawConnection(pin.info.name, slPin);
+                    });
+                }
+            });
+        }
+
+        this.mainTransformer.nodes([]);
+        this.mainLayer.add(this.mainTransformer);
+        this.mainLayer.add(this.selectionRectangle);
+
+        ShapeRegistry.getShapes(this.floorNum).forEach((shape) => shape.displayName(this.textLayer));
+    }
+
 }
Index: imaps-frontend/src/scripts/main/MapDisplay.js
===================================================================
--- imaps-frontend/src/scripts/main/MapDisplay.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/main/MapDisplay.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -3,121 +3,216 @@
 import HttpService from "../net/HttpService.js";
 import {zoomStage} from "../util/zoomStage.js";
+import {addEventHandling} from "../util/addEventHandling.js";
+import triggerNavigate from "../util/triggerNavigate.js";
+import config from "../net/netconfig.js";
+
 export class MapDisplay {
-  constructor(containerId) {
-    this.container = document.getElementById(containerId);
-    this.containerId = containerId;
-    this.stage = new Konva.Stage({
-      container: containerId,
-      width: window.innerWidth,
-      height: window.innerHeight,
-      draggable: true,
-    });
-
-    this.shapes = [];
-    this.loaded = false;
-    this.mainLayer = new Konva.Layer();
-    this.routeLayer = new Konva.Layer();
-    this.textLayer = new Konva.Layer();
-    this.stage.add(this.mainLayer);
-    this.stage.add(this.routeLayer);
-    this.stage.add(this.textLayer);
-    this.route = new Konva.Line();
-
-    this.stage.on("resize", () => {
-      this.stage.width = window.innerWidth;
-      this.stage.height = window.innerHeight;
-    });
-
-    this.stage.on("wheel",(e) => {
-        zoomStage(e,this.stage);
-    })
-
-   
-  }
-
-  deserializeMap(data) {
-    data.forEach((child) => {
-        const shape = JSON.parse(child);
-        if (shape.className !== "InfoPin") {
-            const renderedShape = Factory.createRenderedShape(
-                shape.className,
-                shape.attrs
-            );
-            this.shapes.push(renderedShape);
-      }
-    });
-  }
-
-  displayRoomNames(){
-    console.log("VLEZE")
-    this.shapes.forEach(shape => {
-      shape.displayName(this.textLayer);
-    })
-
-    this.textLayer.children.forEach(child => console.log(child,"DECAAA"));
-  }
-
-  async loadMap() {
-    const httpService = new HttpService();
-    const mapData = await httpService.get("/public/mapData");
-    console.log("DESERIALIZED --->",mapData);
-    this.deserializeMap(mapData);
-    this.shapes.forEach((shape) => {
-      this.mainLayer.add(shape);
-    });
-    this.displayRoomNames();
-  }
-
-  drawRoute(path) {
-    this.routeLayer.removeChildren();
-    console.log("====PATH====");
-    path.forEach((point) => console.log(point.x, point.y));
-
-    const pointsArray = path.flatMap((point) => [point.x, point.y]);
-
-    console.log(pointsArray, "POINTS");
-
-    let buff = [];
-    let count = 0;
-    let index = 0;
-
-    const drawNextSegment = () => {
-        if (index >= pointsArray.length) return;
-
-        buff.push(pointsArray[index]);
-        count++;
-
-        if (count % 4 === 0) {
-            const line = new Konva.Arrow({
-                points: buff,
-                stroke: "#e91332",
-                strokeWidth: 2.5,
-                dash: [5, 4],
-                lineCap: 'round',
-                lineJoin: 'round',
-                pointerLength: 7,
-                pointerWidth: 7,
-                fill:'red',
-            });
-
-            this.routeLayer.add(line);
-            this.routeLayer.draw(); 
-
-            console.log(buff, "BUFFER");
-            buff = []; 
-            index -= 2; 
+    constructor(containerId, floorNum) {
+        this.container = document.getElementById(containerId);
+        this.containerId = containerId;
+        this.stage = new Konva.Stage({
+            container: containerId,
+            width: window.innerWidth,
+            height: window.innerHeight,
+            draggable: true,
+        });
+
+        this.shapes = [];
+        this.roomTypes = [];
+        this.loaded = false;
+        this.mainLayer = new Konva.Layer();
+        this.routeLayer = new Konva.Layer();
+        this.textLayer = new Konva.Layer();
+        this.stage.add(this.mainLayer);
+        this.stage.add(this.routeLayer);
+        this.stage.add(this.textLayer);
+
+        this.floorNum = floorNum;
+
+        this.navArrow = new Konva.Arrow({
+            stroke: "#bb0000",
+            strokeWidth: 3,
+            dash: [12, 7],
+            lineCap: "round",
+            tension: 10,
+            pointerLength: 2,
+            pointerWidth: 3,
+        });
+
+        this.navArrow.cache();
+
+        this.stage.on("resize", () => {
+            this.stage.width = window.innerWidth;
+            this.stage.height = window.innerHeight;
+        });
+
+        this.stage.on("wheel", (e) => {
+            zoomStage(e, this.stage);
+        });
+    }
+
+    clearMap() {
+        this.mainLayer.removeChildren();
+        this.shapes.forEach(shape => shape.clearText())
+        this.shapes = [];
+    }
+
+    deserializeMap(data) {
+        this.clearMap();
+
+        let dsrData = JSON.parse(data);
+        dsrData.forEach((shape) => {
+            if (shape.className !== "InfoPin") {
+                const renderedShape = Factory.createRenderedShape(shape.className, shape.attrs);
+                addEventHandling(renderedShape, this, "click");
+                this.shapes.push(renderedShape);
+            }
+        });
+    }
+
+    displayRoomNames() {
+        this.shapes.forEach((shape) => {
+            shape.displayName(this.textLayer);
+        });
+
+    }
+
+
+
+    loadMapN(floorData) {
+        if (floorData == null || floorData === "") return;
+
+        this.deserializeMap(floorData);
+        this.shapes.forEach((shape) => {
+            this.mainLayer.add(shape);
+        });
+        this.displayRoomNames();
+        this.initializeRoomTypes();
+
+    }
+
+    clearRoute() {
+        this.routeLayer.removeChildren();
+    }
+
+
+    drawRouteNEW(nodes, offset = 0) {
+
+        this.clearRoute();
+        console.log("====PATH====");
+        nodes.forEach((node) => console.log("NODE", node));
+
+        let idx = offset;
+        let buff = [nodes[idx].coordinates.x, nodes[idx].coordinates.y];
+
+
+        ++idx;
+
+        console.log("INIT BUFFER", buff);
+        console.log("INIT IDX", idx);
+
+        const drawNextSegment = () => {
+
+            if (idx >= nodes.length){
+                return;
+            }
+
+            const currentNode = nodes[idx - 1];
+            const nextNode = nodes[idx];
+
+            if (nextNode.floorNumber !== currentNode.floorNumber) {
+                triggerNavigate(nodes, idx, nextNode.floorNumber, nextNode);
+                return;
+            }
+
+            const startX = currentNode.coordinates.x;
+            const startY = currentNode.coordinates.y;
+            const endX = nextNode.coordinates.x;
+            const endY = nextNode.coordinates.y;
+
+            const numSegments = 12;
+
+            const deltaX = (endX - startX) / numSegments;
+            const deltaY = (endY - startY) / numSegments;
+
+            const drawSegment = (i) => {
+                const segmentX = startX + deltaX * i;
+                const segmentY = startY + deltaY * i;
+
+                buff.push(segmentX, segmentY);
+
+                let line = this.navArrow.clone({ points: [...buff] });
+                this.routeLayer.add(line);
+                this.routeLayer.draw();
+
+                buff = [segmentX, segmentY];
+            };
+
+            let segmentIdx = 1;
+            const interval = setInterval(() => {
+                drawSegment(segmentIdx);
+                segmentIdx++;
+
+                if (segmentIdx > numSegments) {
+                    clearInterval(interval);
+                    idx++;
+                    setTimeout(drawNextSegment, 150);
+                }
+            }, 50);
+        };
+
+        drawNextSegment();
+    }
+
+
+
+    initializeRoomTypes() {
+        this.roomTypes = this.shapes
+            .filter((shape) => shape.class === "Room" && shape.info.type !== "")
+            .map((shape) => shape.info.type);
+    }
+
+    getRoomTypes() {
+        return this.roomTypes;
+    }
+
+
+    getShapeByName(name){
+        return this.shapes.find(shape => shape.info.name === name)
+    }
+
+    getShapeByType(type) {
+        return this.shapes.filter((shape) => shape.class === type)
+    }
+
+    toggleSearchRoom() {
+        this.toggleSearch = !this.toggleSearch;
+    }
+
+    //ova e loso ne trebit vaka
+    highlightShape(roomName) {
+        let foundShape = this.shapes.filter((shape) => shape.info.name === roomName)[0];
+        foundShape.highlight();
+    }
+
+    getMainEntrance() {
+        return this.shapes.filter(shape => shape.class === "Entrance").filter(el => el.info.isMainEntrance === true)[0];
+    }
+
+    setFilter(filter) {
+        let rooms = this.getShapeByType("Room")
+        if (filter === "All") {
+            rooms.forEach((shape) => {
+                shape.unHighlight()
+            })
+        } else {
+            rooms.filter((shape) => shape.info.type === filter).forEach((shape) => {
+                shape.highlight()
+            })
+            rooms.filter((shape) => shape.info.type !== filter).forEach((shape) => {
+                shape.unHighlight()
+            })
         }
 
-        index++;
-
-        setTimeout(drawNextSegment, 25); 
-    };
-
-    drawNextSegment(); 
+    }
 }
-
-
-  search() {
-    console.log("VLEZE VO SEARCH");
-  }
-}
Index: imaps-frontend/src/scripts/net/HttpService.js
===================================================================
--- imaps-frontend/src/scripts/net/HttpService.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/net/HttpService.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -3,6 +3,5 @@
 
 class HttpService {
-    constructor(URL = config.apiBaseUrl, auth = false) {
-      this.baseURL = URL;
+    constructor(auth = false) {
       this.auth = auth;
     }
@@ -33,5 +32,5 @@
       }
   
-      const response = await fetch(`${this.baseURL}${endpoint}`, options);
+      const response = await fetch(`${endpoint}`, options);
       
       if (!response.ok) {
Index: imaps-frontend/src/scripts/net/netconfig.js
===================================================================
--- imaps-frontend/src/scripts/net/netconfig.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/net/netconfig.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -1,14 +1,57 @@
+export const API_BASE_URL = "http://localhost:8080/api";
+export const API_PROTECTED = `${API_BASE_URL}/protected`
+export const API_PUBLIC = `${API_BASE_URL}/public`
+export const API_AUTH = `${API_BASE_URL}/auth`
+
 
 const config = {
-    apiBaseUrl: "http://localhost:8080/api",
+    my_maps: {
+        display: `${API_PROTECTED}/my-maps`,
+        save: `${API_PROTECTED}/my-maps/save`,
+        add: `${API_PROTECTED}/my-maps/create`,
+        load: `${API_PROTECTED}/my-maps/load`,
+        delete: `${API_PROTECTED}/my-maps/delete`,
+        publish: `${API_PROTECTED}/publish/add`,
+        publish_get: `${API_PROTECTED}/publish/get`,
+    },
+    room_types: {
+        display: (auth) => {
+            return auth ? `${API_PROTECTED}/room-types` : `${API_PUBLIC}/room-types`
+        },
+        add: `${API_PROTECTED}/room-types/add`,
 
-    endpoints: {
-        login: "/auth/login",
-        register: "/auth/register",
-        verify: "/auth/verify",
-        render: "/protected/render",
-        publicMapData: "/public/mapData"
+    },
+    floors: {
+        add: `${API_PROTECTED}/floors/add`,
+        load: `${API_PROTECTED}/my-maps/load`,
+        delete: `${API_PROTECTED}/floors/delete`,
+    },
+    view_maps: {
+        display: `${API_PUBLIC}/maps`,
+        load: (auth) => {
+            return auth ? `${API_PROTECTED}/load-map` : `${API_PUBLIC}/load-map`
+        },
+        navigate: `${API_PUBLIC}/navigate`,
+        add_favourite: `${API_PROTECTED}/favourites/add`,
+    },
+    favourites: {
+        display: `${API_PROTECTED}/favourites`,
+        add: `${API_PROTECTED}/favourites/add`,
+        delete: `${API_PROTECTED}/favourites/delete`,
+    },
+    auth:{
+        login: `${API_AUTH}/login`,
+        register: `${API_AUTH}/register`,
+        verify: `${API_AUTH}/verify`
+
+    },
+    admin:{
+        display: `${API_BASE_URL}/admin`,
+        load_pr: `${API_BASE_URL}/admin/load-pr`,
+        approve_pr: `${API_BASE_URL}/admin/pr/approve`,
+        deny_pr: `${API_BASE_URL}/admin/pr/deny`
     }
 };
 
+
 export default config;
Index: imaps-frontend/src/scripts/rendered_shapes/RenderedEntrance.js
===================================================================
--- imaps-frontend/src/scripts/rendered_shapes/RenderedEntrance.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/rendered_shapes/RenderedEntrance.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -1,37 +1,44 @@
-import RenderedMapShape from "./RenderedMapShape.js";
+import RenderedMapShape from "../base/RenderedMapShape.js";
+import {_registerNode} from "konva/lib/Global";
+import RenderedRoom from "./RenderedRoom.js";
 
-export default class RenderedEntrance extends RenderedMapShape{
-    constructor(attrs,scaleX,scaleY){
-        super({
-            x: attrs.x,
-            y: attrs.y,
-            width: attrs.width * scaleX,
-            height: attrs.height * scaleY,
-            fill: '#1c3cff',
-            stroke: 'black',
-            strokeWidth: 1,
-            draggable: false,
-            rotation: attrs.rotation,
-            cornerRadius:3,
-            zIndex: 0
-        });
+export default class RenderedEntrance extends RenderedMapShape {
+  constructor(attrs, scaleX, scaleY) {
+    super({
+      x: attrs.x,
+      y: attrs.y,
+      width: attrs.width * scaleX,
+      height: attrs.height * scaleY,
+      fill: "#7fef83",
+      stroke: "black",
+      strokeWidth: 1,
+      draggable: false,
+      rotation: attrs.rotation,
+      cornerRadius: 3,
+      zIndex: 0,
+    });
 
-        this.info.name = attrs.obj_name;
-        this.info.description = attrs.description;
-        
-    
-        this.on("mouseenter",() => {
-        console.log("HOVER ROOM IN", this.x());
-        console.log(this.info.name,"NAME");
-        this.stroke('purple');
-        })
-        this.on("mouseleave", () => {
-            console.log("HOVER ROOM OUT");
-            this.opacity(1);
-            this.stroke('black')
+    this.info.name = attrs.obj_name;
+    this.info.description = attrs.description;
+    this.info.isMainEntrance = attrs.is_main_entrance;
 
-        })
+    this.floorNum = attrs.floor_num
 
-        this.initText()
-    }
+    this.class = "Entrance";
+
+    console.log("ATTRS VIEW:  " + attrs)
+
+    this.on("mouseenter", () => {
+      this.stroke("purple");
+    });
+    this.on("mouseleave", () => {
+      this.opacity(1);
+      this.stroke("black");
+    });
+
+    //this.initText();
+  }
 }
+
+RenderedEntrance.prototype.className = "RenderedEntrance";
+_registerNode(RenderedEntrance);
Index: imaps-frontend/src/scripts/rendered_shapes/RenderedMapShape.js
===================================================================
--- imaps-frontend/src/scripts/rendered_shapes/RenderedMapShape.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ 	(revision )
@@ -1,45 +1,0 @@
-import Konva from "konva";
-
-export default class RenderedMapShape extends Konva.Rect{
-    constructor(config){
-        if (new.target === RenderedMapShape) {
-            throw new Error("Cannot instantiate abstract class RenderedMapShape directly.");
-          }
-
-          super(config);
-
-          this.info = {
-            name: "",
-            description: "",
-          }
-          this.infoText = null;
-          this.textOffsetX = 0;
-          this.textOffsetY = 0;
-    }
-
-    initText() {
-      this.infoText = new Konva.Text({
-        x: this.x() + this.textOffsetX,
-        y: this.y() + this.textOffsetY,
-        text: this.info.name || "no name",
-        fontSize: 12,
-        fontFamily: 'Verdana',
-        fill: 'black',
-      });
-    }
-  
-    updateTextPosition() {
-      if(this.infoText){
-        this.infoText.x(this.x() + this.textOffsetX);
-        this.infoText.y(this.y() + this.textOffsetY);
-      }
-    }
-  
-    displayName(layer) {
-        if(this.infoText != null){
-            layer.add(this.infoText);
-        }
-
-    }
-    
-}
Index: imaps-frontend/src/scripts/rendered_shapes/RenderedRoom.js
===================================================================
--- imaps-frontend/src/scripts/rendered_shapes/RenderedRoom.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/rendered_shapes/RenderedRoom.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -1,41 +1,62 @@
-import RenderedMapShape from "./RenderedMapShape.js";
+import RenderedMapShape from "../base/RenderedMapShape.js";
+import {_registerNode} from "konva/lib/Global";
 
-export default class RenderedRoom extends RenderedMapShape{
-    constructor(attrs,scaleX,scaleY){
-        super({
-            x: attrs.x,
-            y: attrs.y,
-            width: attrs.width * scaleX,
-            height: attrs.height * scaleY,
-            fill: 'white',
-            stroke: 'black',
-            strokeWidth: 1,
-            draggable: false,
-            rotation: attrs.rotation,
-            cornerRadius:3,
-            zIndex: 0
-        });
+export default class RenderedRoom extends RenderedMapShape {
+  constructor(attrs, scaleX, scaleY) {
+    super({
+      x: attrs.x,
+      y: attrs.y,
+      width: attrs.width * scaleX,
+      height: attrs.height * scaleY,
+      fill: "#A2D9FF",
+      stroke: "black",
+      strokeWidth: 1,
+      draggable: false,
+      rotation: attrs.rotation,
+      cornerRadius: 3
+    });
 
-        this.info.name = attrs.obj_name;
-        this.info.description = attrs.description;
+    console.info("FNUM RENDER:",attrs.floor_num)
 
-        this.textOffsetX = -50
-        
-    
-        this.on("mouseenter",() => {
-        console.log("HOVER ROOM IN", this.x());
-        console.log(this.info.name,"NAME");
-        this.opacity(0.7);
-        this.fill("pink");
-        })
-        this.on("mouseleave", () => {
-            console.log("HOVER ROOM OUT");
-            this.opacity(1);
-            this.fill("white");
-        })
+    this.floorNum = attrs.floor_num
 
-        this.initText()
-    }
+    this.info.name = attrs.obj_name;
+    this.info.type = attrs.room_type;
+    this.info.description = attrs.description;
+    this.class = "Room";
+    this.textOffsetX = -50;
 
-   
+    this.eventName = "openRoomInfoPanel"
+
+    this.on("mouseenter", () => {
+      console.log(this.info.name, "NAME");
+      this.fill("#65c3f8");
+    });
+    this.on("mouseleave", () => {
+      this.fill("#A2D9FF");
+    });
+
+
+
+    // searched(){
+    //   this.fill("#b92d39")
+    // }
+    // unsearched(){
+    //   this.fill("#A2D9FF");
+    // }
+
+    // console.log("ATTRS: " + attrs);
+
+    this.initText();
+  }
+  highlight(){
+    this.fill("rgba(29,238,78,0.49)");
+    this.strokeWidth(2)
+  }
+  unHighlight(){
+    this.fill("#A2D9FF");
+    this.strokeWidth(1);
+  }
 }
+RenderedRoom.prototype.className = "RenderedRoom";
+_registerNode(RenderedRoom);
Index: imaps-frontend/src/scripts/rendered_shapes/RenderedStairs.js
===================================================================
--- imaps-frontend/src/scripts/rendered_shapes/RenderedStairs.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/rendered_shapes/RenderedStairs.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,43 @@
+import RenderedMapShape from "../base/RenderedMapShape.js";
+import Stairs from "../shapes/Stairs.js";
+import {_registerNode} from "konva/lib/Global";
+import Konva from "konva";
+export default class RenderedStairs extends RenderedMapShape{
+    constructor(attrs,scaleX,scaleY) {
+        super({
+            x: attrs.x,
+            y: attrs.y,
+            width: attrs.width * scaleX,
+            height: attrs.height * scaleY,
+            fill: "rgb(199,190,133)",
+            stroke: "rgb(16,15,15)",
+            strokeWidth: 1,
+            name: "mapObj",
+            rotation: attrs.rotation,
+        });
+
+
+        this.floorNum = attrs.floor_num;
+        this.info.name = attrs.obj_name;
+        //this.initText()
+    }
+
+
+
+
+    _sceneFunc(context, shape) {
+        const { width, height} = this.attrs;
+
+        let steps = 5;
+        let offset = 10;
+        context.beginPath()
+        for(let i = 0; i < steps; i++){
+            context.rect((-offset) * i,(offset * 0.6) * i,width * 0.86,height/2)
+            context.fillStrokeShape(shape);
+        }
+        context.closePath()
+    }
+}
+
+RenderedStairs.prototype.className = "RenderedStairs";
+_registerNode(RenderedStairs);
Index: imaps-frontend/src/scripts/rendered_shapes/RenderedWall.js
===================================================================
--- imaps-frontend/src/scripts/rendered_shapes/RenderedWall.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/rendered_shapes/RenderedWall.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -1,3 +1,4 @@
-import RenderedMapShape from "./RenderedMapShape.js";
+import RenderedMapShape from "../base/RenderedMapShape.js";
+import {_registerNode} from "konva/lib/Global";
 
 export default class RenderedWall extends RenderedMapShape{
@@ -8,5 +9,5 @@
             width: attrs.width * scaleX,
             height: attrs.height * scaleY,
-            fill: 'grey',
+            fill: '#4B4B4B',
             stroke: 'black',
             strokeWidth: 1,
@@ -18,2 +19,5 @@
     }
 }
+
+RenderedWall.prototype.className = "RenderedWall";
+_registerNode(RenderedWall);
Index: imaps-frontend/src/scripts/shapes/Entrance.js
===================================================================
--- imaps-frontend/src/scripts/shapes/Entrance.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/shapes/Entrance.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -1,58 +1,88 @@
-import Konva from "konva";
-import MapShape from "./MapShape";
-import { _registerNode } from "konva/lib/Global";
-export default class Entrance extends MapShape {
-  constructor(mousePos, blockSize, layer, rotation, snap,id,scaleX = 1, scaleY = 1) {
-    super(
-      {
-        x: mousePos.x,
-        y: mousePos.y,
-        width: blockSize * scaleX,
-        height: blockSize * 2 * scaleY,
-        fill: "#0051ff",
-        stroke: "grey",
-        strokeWidth: 1,
-        opacity: 0.7,
-        name: "mapObj",
-        draggable: true,
-        rotation: rotation,
-        zIndex: 1,
-      },
-      layer,
-      blockSize,
-      snap
-    );
-    this.type = "Entrance";
-    this.modalEventName = "openEntranceModalEvent";
+import {_registerNode} from "konva/lib/Global";
+import MapNode from "../base/MapNode.js";
+import {node} from "prop-types";
 
-    this.id = id;
+export default class Entrance extends MapNode {
 
-    this._info = {
-      name: `Entrance ${id}`,
-      connectedRoom: "",
-      description: "",
-      isMainEntrance: false,
-      selectedPin: "",
-      selectedPins: [],
-    };
+    constructor(attrs, id) {
 
-    this.initText();
-  }
+        if (!attrs.fromLoad) {
+            attrs.height *= 2;
+        }
+        super(
+            {
+                x: attrs.position.x,
+                y: attrs.position.y,
+                width: attrs.width,
+                height: attrs.height,
+                fill: "rgb(126,238,167)",
+                stroke: "#252627",
+                strokeWidth: 1,
+                opacity: 0.9,
+                name: "mapObj",
+                draggable: true,
+                rotation: attrs.rotation,
+                zIndex: 1,
+            },
+            attrs.layer,
+            attrs.blockSize,
+            attrs.snap
+        );
+        this.type = "Entrance";
+        this.eventName = "openEntranceModalEvent";
+        this.floorNum = attrs.floorNum
 
-  loadInfo(attrs) {
-    this.info.name = attrs.obj_name;
-    this.info.connectedRoom = attrs.connected_room;
-    this.info.description = attrs.description;
-    this.info.isMainEntrance = attrs.is_main_entrance;
-    this.info.selectedPins = attrs.connected_pins;
-  }
+        this.id = id;
 
-  saveShapeDetails() {
-    this.setAttr("connected_pins", this.info.selectedPins);
-    this.setAttr("obj_name", this.info.name);
-    this.setAttr("description", this.info.description);
-    this.setAttr("is_main_entrance", this.info.isMainEntrance);
-    this.setAttr("connected_room", this.info.connectedRoom);
-  }
+        this._info = {
+            name: `Entrance${id} [${this.floorNum}F]`,
+            connectedRoom: "",
+            description: "",
+            isMainEntrance: false,
+            selectedPin: "",
+            selectedPins: [],
+        };
+
+        this.initText();
+        this.moveToTop();
+    }
+
+    loadInfo(attrs) {
+        this.info.name = attrs.obj_name;
+        this.info.connectedRoom = attrs.connected_room;
+        this.info.description = attrs.description;
+        this.info.isMainEntrance = attrs.is_main_entrance;
+        this.info.selectedPins = attrs.connected_pins;
+        this.floorNum = attrs.floor_num;
+    }
+
+    saveShapeDetails() {
+        console.info("fnum entrance",this.attrs.floorNum)
+
+        this.setAttr("connected_pins", this.info.selectedPins);
+        this.setAttr("obj_name", this.info.name);
+        this.setAttr("description", this.info.description);
+        this.setAttr("is_main_entrance", this.info.isMainEntrance);
+        this.setAttr("connected_room", this.info.connectedRoom);
+        this.setAttr("floor_num",this.floorNum);
+    }
+
+    connect(node, draw = true) {
+        if(this.floorNum !== node.floorNum) return;
+
+        super.connect(node)
+    }
+
+    setInfo(infoObj) {
+        console.log("SA VIKNA SETINFO")
+        this.info = infoObj;
+        if(this.info.connectedRoom == null || this.info.connectedRoom === "" ){
+            this.strokeWidth(2);
+            this.stroke("#a10114")
+        }else{
+            this.strokeWidth(1)
+            this.stroke("black")
+        }
+    }
 }
 
Index: imaps-frontend/src/scripts/shapes/InfoPin.js
===================================================================
--- imaps-frontend/src/scripts/shapes/InfoPin.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/shapes/InfoPin.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -1,32 +1,35 @@
-import Konva from "konva";
-import MapShape from "./MapShape";
-import Factory from "../util/Factory";
+
 import { _registerNode } from "konva/lib/Global";
-export default class InfoPin extends MapShape {
-  constructor(mousePos, blockSize, layer, snappable,id) {
+import MapNode from "../base/MapNode.js";
+import {node} from "prop-types";
+import draw from "../../pages/Draw/Draw.jsx";
+export default class InfoPin extends MapNode {
+  constructor(attrs,id) {
+    attrs.snap = false;
     super(
       {
-        x: mousePos.x,
-        y: mousePos.y,
-        radiusX: blockSize * 0.5,
-        radiusY: blockSize * 0.7,
-        tailHeight: blockSize * 1.2,
-        fill: "#d70113",
+        x: attrs.position.x,
+        y: attrs.position.y,
+        radiusX: attrs.blockSize * 0.5,
+        radiusY: attrs.blockSize * 0.7,
+        tailHeight: attrs.blockSize * 1.2,
+        fill: "#f60000",
         stroke: "#1b1b1b",
-        strokeWidth: 0.2,
+        strokeWidth: 1,
         draggable: true,
         name: "mapObj",
       },
-      layer,
-      blockSize,
-      snappable
+      attrs.layer,
+      attrs.blockSize,
+      attrs.snap
     );
 
     this.id = id;
+    this.eventName = "openPinModalEvent";
+    this.floorNum = attrs.floorNum;
 
-    this.modalEventName = "openPinModalEvent";
     this.type = "InfoPin";
     this._info = {
-      name: `Pin ${id}`,
+      name: `Pin${id} [${this.floorNum}F]`,
       selectedPins: [],
       description: "",
@@ -34,14 +37,15 @@
 
     this.on("mouseover", () => {
-      this.fill("yellow");
+      this.fill("#FFD700");
     });
     this.on("mouseout", () => {
-      this.fill("red");
+      this.fill("#f60000");
     });
+
 
     this.initText();
   }
   _sceneFunc(context, shape) {
-    const { radiusX, radiusY, tailHeight } = this.attrs;
+    const { radiusX, radiusY, tailHeight } = this.attrs; // attrs od konva
 
     context.beginPath();
@@ -59,8 +63,10 @@
   }
 
+
   loadInfo(attrs) {
     this.info.name = attrs.obj_name;
     this.info.selectedPins = attrs.connected_pins;
     this.info.description = attrs.description;
+    this.floorNum = attrs.floor_num
   }
 
@@ -69,5 +75,11 @@
     this.setAttr("connected_pins", this.info.selectedPins);
     this.setAttr("description", this.info.description);
+    this.setAttr("floor_num",this.floorNum)
     console.log(this.info, "vnatre vo info");
+  }
+
+  connect(node, draw = true) {
+    if(this.floorNum !== node.floorNum) return;
+    super.connect(node)
   }
 }
Index: imaps-frontend/src/scripts/shapes/MapShape.js
===================================================================
--- imaps-frontend/src/scripts/shapes/MapShape.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ 	(revision )
@@ -1,123 +1,0 @@
-import Konva from "konva";
-
-export default class MapShape extends Konva.Shape {
-    constructor(config, layer, blockSize, snap) {
-        if (new.target === MapShape) {
-            throw new Error("Cannot instantiate abstract class BaseShape directly.");
-        }
-        super(config);
-        this.layer = layer;
-        this.blockSize = blockSize;
-        this._type = "";
-        this.snappable = snap;
-        this._info = {};
-        this.modalEventName = "";
-        this.infoText = null;
-
-        this.shadowForStrokeEnabled(false);
-        this.on("mouseover", () => (document.body.style.cursor = "pointer"));
-        this.on("mouseout", () => (document.body.style.cursor = "default"));
-        // this.on("dblclick", (e) => {
-        //   this.moveToTop();
-        //   this.getLayer()
-        //     .find("Transformer")
-        //     .forEach((t) => t.moveToTop());
-        // });
-
-        if (snap) {
-            this.on("dragend", this.snapToGrid.bind(this));
-            this.on('dblclick', this.snapToGrid.bind(this))
-        }
-
-        this.on("transform", () => {
-            const scaleX = this.scaleX();
-            const scaleY = this.scaleY();
-            this.strokeWidth(1 / Math.max(scaleX, scaleY));
-        });
-
-        this.on('dragend', () => {
-            if (this.infoText) {
-                this.updateTextPosition();
-            }
-        });
-
-    }
-
-    loadInfo(attrs) {
-        console.log("Abstract function");
-    }
-
-
-    initText() {
-        this.textOffsetX = 0;
-        this.textOffsetY = -30;
-        this.infoText = new Konva.Text({
-            x: this.x() + this.textOffsetX,
-            y: this.y() + this.textOffsetY,
-            text: this._info.name,
-            fontSize: 12,
-            fontFamily: 'Verdana',
-            fill: 'white',
-        });
-    }
-
-    updateTextPosition() {
-        if (this.infoText) {
-            this.infoText.x(this.x() + this.textOffsetX);
-            this.infoText.y(this.y() + this.textOffsetY);
-        }
-    }
-
-    displayName(layer) {
-        if (this.infoText) {
-            this.infoText.text(this._info.name);
-            layer.add(this.infoText);
-        }
-    }
-
-    _sceneFunc(context) {
-        let width = this.width();
-        let height = this.height();
-        context.beginPath();
-        context.rect(0, 0, width, height)
-        context.closePath();
-        context.fillStrokeShape(this);
-    }
-
-    clearText() {
-        if (this.infoText !== null) {
-            this.infoText.remove()
-            console.log("cleared text")
-        }
-
-    }
-
-    snapToGrid() {
-        this.position({
-            x: Math.round(this.x() / this.blockSize) * this.blockSize,
-            y: Math.round(this.y() / this.blockSize) * this.blockSize,
-        });
-    }
-
-    saveShapeDetails() {
-        console.log("This shape does not contain information");
-    }
-
-
-    get info() {
-        return this._info;
-    }
-
-    set info(formData) {
-        this._info = formData;
-    }
-
-    get type() {
-        return this._type;
-    }
-
-    set type(type) {
-        this._type = type
-    }
-
-}
Index: imaps-frontend/src/scripts/shapes/Room.js
===================================================================
--- imaps-frontend/src/scripts/shapes/Room.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/shapes/Room.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -1,27 +1,36 @@
 import Konva from "konva";
-import MapShape from "./MapShape";
+import MapShape from "../base/MapShape.js";
 import { _registerNode } from "konva/lib/Global";
 export default class Room extends MapShape {
-  constructor(mousePos, blockSize, layer, rotation, snap, id, scaleX = 1, scaleY = 1){
+  constructor(attrs,id){
+
+      if(!attrs.fromLoad){
+          attrs.width *= 12;
+          attrs.height *= 8;
+      }
+
+      console.log(attrs.position,"hehe")
     super(
       {
-        x: mousePos.x,
-        y: mousePos.y,
-        width: blockSize * 8 * scaleX,
-        height: blockSize * 4 * scaleY,
-        fill: "#DDE0F8",
+        x: attrs.position.x,
+        y: attrs.position.y,
+        width: attrs.width * attrs.scaleX,
+        height: attrs.height * attrs.scaleY,
+        fill: "rgb(86,168,253)",
         stroke: "grey",
         strokeWidth: 1,
         name: "mapObj",
-        rotation: rotation,
+        rotation: attrs.rotation,
         draggable: true,
       },
-      layer,
-      blockSize,
-      snap
+        attrs.layer,
+        attrs.blockSize,
+        attrs.snap
     );
 
+      this.floorNum = attrs.floorNum;
+
     this._info = {
-      name: `Room ${id}`,
+      name: `Room${id} [${this.floorNum}F]`,
       type: "",
       description: "",
@@ -29,5 +38,5 @@
 
     this.type = "Room";
-    this.modalEventName = "openRoomModalEvent";
+    this.eventName = "openRoomModalEvent";
     this.id = id;
 
@@ -39,4 +48,5 @@
     this.info.type = attrs.room_type;
     this.info.description = attrs.description;
+    this.floorNum = attrs.floor_num;
   }
 
@@ -45,4 +55,5 @@
     this.setAttr("room_type", this.info.type);
     this.setAttr("description", this.info.description);
+    this.setAttr("floor_num",this.floorNum);
   }
 }
Index: imaps-frontend/src/scripts/shapes/Stairs.js
===================================================================
--- imaps-frontend/src/scripts/shapes/Stairs.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/shapes/Stairs.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -1,4 +1,78 @@
 import Konva from "konva";
-import { MapShape } from "./MapShape";
+import MapNode from "../base/MapNode.js";
+import {_registerNode} from "konva/lib/Global.js";
+import Room from "./Room.js";
+export default class Stairs extends MapNode{
+    constructor(attrs,id) {
 
+        if(!attrs.fromLoad){
+            attrs.width *= 4;
+        }
+
+        super({
+                x: attrs.position.x,
+                y: attrs.position.y,
+                width: attrs.width * attrs.scaleX,
+                height: attrs.height * attrs.scaleY,
+                fill: "rgb(225,213,124)",
+                stroke: "rgb(16,15,15)",
+                strokeWidth: 1,
+                name: "mapObj",
+                rotation: attrs.rotation,
+                draggable: true
+            },
+            attrs.layer,
+            attrs.blockSize,
+            attrs.snap
+        );
+
+        this.floorNum = attrs.floorNum;
+
+        this.type = "Stairs"
+        this._info = {
+            name: `Stairs${id} [${this.floorNum}F]`,
+            description: "",
+            selectedPins: []
+        };
+
+        this.id = id;
+        this.eventName = "openStairsModalEvent";
+        this.initText();
+    }
+
+
+    _sceneFunc(context, shape) {
+        const { width, height} = this.attrs;
+
+        let steps = 5;
+        context.beginPath()
+        for(let i = 0; i < steps; i++){
+            context.rect((-this.blockSize) * i,(this.blockSize * 0.6) * i,width * 0.86,height/2)
+            context.fillStrokeShape(shape);
+        }
+        context.closePath()
+    }
+
+    loadInfo(attrs) {
+        this.info.name = attrs.obj_name;
+        this.info.description = attrs.description;
+        this.info.selectedPins = attrs.connected_pins;
+        this.floorNum = attrs.floor_num;
+    }
+
+    saveShapeDetails() {
+        this.setAttr("connected_pins", this.info.selectedPins);
+        this.setAttr("obj_name", this.info.name);
+        this.setAttr("description", this.info.description);
+        this.setAttr("floor_num",this.floorNum)
+    }
+    connect(node,draw = true) {
+        let canDraw = this.floorNum === node.floorNum;
+        super.connect(node,canDraw);
+    }
+
+}
+
+Stairs.prototype.className = "Stairs";
+_registerNode(Stairs);
 //TODO
Index: imaps-frontend/src/scripts/shapes/Wall.js
===================================================================
--- imaps-frontend/src/scripts/shapes/Wall.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/shapes/Wall.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -1,29 +1,43 @@
 import Konva from "konva";
-import MapShape from "./MapShape";
+import MapShape from "../base/MapShape.js";
 import { _registerNode } from 'konva/lib/Global';
 export default class Wall extends MapShape {
-    constructor(mousePos, blockSize, layer, rotation,snap, draggable = true,scaleX = 1, scaleY = 1){
+    constructor(attrs){
+        if(!attrs.fromLoad){
+            attrs.height *= 8;
+        }
+
+
       super(
         {
-          x: mousePos.x,
-          y: mousePos.y,
-          width: blockSize * scaleX,
-          height: blockSize * 8 * scaleY,
-          fill: "#DDE0F8",
+          x: attrs.position.x,
+          y: attrs.position.y,
+          width: attrs.width * attrs.scaleX,
+          height: attrs.height * attrs.scaleY,
+          fill: "#d3d3d3",
           stroke: "grey",
           strokeWidth: 1,
           name: "mapObj",
-          draggable: draggable,
-          rotation: rotation,
+          draggable: true,
+          rotation: attrs.rotation,
           zIndex: 0,
         },
-        layer,
-        blockSize,
-        snap,
+        attrs.layer,
+        attrs.blockSize,
+        attrs.snap,
       );
-  
       this.type = "Wall";
+
+        this.floorNum = attrs.floorNum;
     }
-  }
+
+    loadInfo(attrs) {
+        this.floorNum = attrs.floor_num;
+    }
+
+    saveShapeDetails() {
+        this.setAttr("floor_num",this.floorNum)
+    }
+}
 
   Wall.prototype.className = 'Wall'
Index: imaps-frontend/src/scripts/util/Factory.js
===================================================================
--- imaps-frontend/src/scripts/util/Factory.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/util/Factory.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -6,24 +6,35 @@
 import RenderedEntrance from "../rendered_shapes/RenderedEntrance";
 import RenderedWall from "../rendered_shapes/RenderedWall.js";
+import Stairs from "../shapes/Stairs.js";
+import RenderedStairs from "../rendered_shapes/RenderedStairs.js";
+import {updateShapeCount, getShapeCount} from "./ShapeCount.js";
 export default class Factory {
+  // BUG KO KE NAPRES REFRESH SA RESETVAT COUNTS!
 
-  static infoPinCount = 0;
-  static wallCount = 0;
-  static entranceCount = 0;
-  static roomCount = 0;
+  static createShape(shapeType,attrs) {
+    console.log(attrs,"attrs in factory")
+    console.log("position in factory: " + attrs.position.x)
 
-  static createShape(shapeType, position, blockSize, layer, rotation,scaleX = 1, scaleY = 1, increment = false) {
+    let scaleX = (attrs.scaleX ? parseFloat(attrs.scaleX) : 1);
+    let scaleY =  (attrs.scaleY ? parseFloat(attrs.scaleY) : 1);
+
+    attrs.scaleX = scaleX;
+    attrs.scaleY = scaleY;
+
     switch (shapeType) {
       case "Entrance":
-        if(increment) this.entranceCount++;
-        return new Entrance(position, blockSize, layer, rotation,true,this.entranceCount,scaleX,scaleY);
+        if(attrs.increment) updateShapeCount("entrance")
+        return new Entrance(attrs,getShapeCount("entrance"));
       case "Room":
-        if(increment) this.roomCount++;
-        return new Room(position, blockSize, layer, rotation,true, this.roomCount,scaleX,scaleY);
-      case "Wall":
-        return new Wall(position, blockSize, layer, rotation,true,scaleX,scaleY);
-      case "InfoPin":
-        if(increment) this.infoPinCount++;
-        return new InfoPin(position, blockSize, layer, false,this.infoPinCount);
+        if(attrs.increment) updateShapeCount("room");
+        return new Room(attrs,getShapeCount("room"));
+       case "Wall":
+         return new Wall(attrs);
+       case "InfoPin":
+        if(attrs.increment) updateShapeCount("infoPin")
+          return new InfoPin(attrs,getShapeCount("infoPin"));
+      case "Stairs":
+        if(attrs.increment) updateShapeCount("stairs")
+        return new Stairs(attrs,getShapeCount("stairs"))
       default:
         throw new Error("Invalid shape type: " + shapeType);
@@ -41,4 +52,6 @@
       case "Wall":
         return new RenderedWall(attrs,scaleX,scaleY);
+      case "Stairs":
+        return new RenderedStairs(attrs,scaleX,scaleY)
       default:
         throw new Error("Invalid shape type." + shapeType);
Index: imaps-frontend/src/scripts/util/ShapeCount.js
===================================================================
--- imaps-frontend/src/scripts/util/ShapeCount.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/util/ShapeCount.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,18 @@
+const shapeCount = {
+    infoPin: 0,
+    wall: 0,
+    entrance: 0,
+    room: 0,
+    stairs: 0
+};
+
+const updateShapeCount = (key) => {
+    shapeCount[key]++;
+}
+const getShapeCount = (key) => {
+    return shapeCount[key];
+}
+
+export {updateShapeCount, getShapeCount};
+
+// todo za da sa incrementvit i posle restart na browwser, trebit vo baza nova tabela za broenje
Index: imaps-frontend/src/scripts/util/ShapeQuery.js
===================================================================
--- imaps-frontend/src/scripts/util/ShapeQuery.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/util/ShapeQuery.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,19 @@
+import MapNode from "../base/MapNode.js";
+import ShapeRegistry from "./ShapeRegistry.js";
+
+export default class ShapeQuery{
+    static findAllByType(...types) {
+        return ShapeRegistry.getShapes().filter(shape => types.includes(shape.className));
+    }
+
+    static findNodeByName(shapes, name){
+        return shapes.filter(shape => shape instanceof MapNode && shape.info.name === name)[0];
+    }
+    static findAllByTypeAndFloor(floor,...types){
+        return ShapeRegistry.getShapes().filter(shape => types.includes(shape.className) && shape.floorNum === floor);
+    }
+
+    static getAllNodes(floor = null){
+        return ShapeRegistry.getShapes(floor).filter(shape => shape instanceof MapNode);
+    }
+}
Index: imaps-frontend/src/scripts/util/ShapeRegistry.js
===================================================================
--- imaps-frontend/src/scripts/util/ShapeRegistry.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/util/ShapeRegistry.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,165 @@
+import MapNode from "../base/MapNode.js";
+import ShapeQuery from "./ShapeQuery.js";
+// TODO abstraktna klasa ova da stanit i za da napram za view registry, za da mozis search na floors globalno
+
+class ShapeRegistry {
+    constructor() {
+        if (!ShapeRegistry.instance) {
+            this.store = {
+                floors: {} // key brojka 0: shappes arr
+            };
+            ShapeRegistry.instance = this;
+        }
+
+        return ShapeRegistry.instance;
+    }
+
+    /**
+     * @description Get all the shapes from a floor if floorNumber is specified.
+     * @description If floorNumber is not specified, returns all the shapes from every floor.
+     * @param floorNumber
+     * @returns {[{}]} [shapes]
+     */
+    getShapes(floorNumber = null) {
+        if (!this.store.floors[floorNumber]) {
+            this.store.floors[floorNumber] = [];
+        }
+
+        if (floorNumber != null) {
+            return this.store.floors[floorNumber];
+        } else {
+            return Object.values(this.store.floors).flat();
+        }
+
+
+    }
+
+    /**
+     * Adds a shape to a floor that corresponds the shape's internally stored floor number.
+     * @param shape
+     */
+    add(shape) {
+        console.log("floor: " + shape.floorNum)
+        if (!this.store.floors[shape.floorNum]) {
+            this.store.floors[shape.floorNum] = [];
+        }
+        this.store.floors[shape.floorNum].push(shape);
+    }
+
+    /**
+     * Deletes a shape from the floor corresponds the shape's internally stored floor number
+     * @param shape
+     */
+    delete(shape) {
+        const floorShapes = this.store.floors[shape.floorNum];
+        if (floorShapes) {
+            const index = floorShapes.indexOf(shape);
+            if (index !== -1) {
+                floorShapes.splice(index, 1);
+            }
+        }
+    }
+
+    /**
+     * @param floorNumber Clears all shapes from the specified floor
+     */
+    clear(floorNumber = null) {
+
+        if(floorNumber != null){
+            const floor = this.store.floors[floorNumber];
+            if (Array.isArray(floor)) {
+                floor.forEach(shape => shape.destroy());
+                this.store.floors[floorNumber] = [];
+            }
+        } else {
+           Object.keys(this.store.floors).forEach(floorNumber => {
+               const floor = this.store.floors[floorNumber];
+               if (Array.isArray(floor)) {
+                   floor.forEach(shape => shape.destroy());
+                   this.store.floors[floorNumber] = [];
+               }
+           })
+        }
+
+
+
+    }
+
+    // ova mozit optimizacija da ne pret na site spratoj update celo vreme, samo ko ke povrzvis stairs da pret na site
+    updateConnections() {
+        Object.values(this.store.floors).forEach(floorShapes => {
+            floorShapes.forEach(shape => {
+                if (shape.className === "InfoPin" || shape.className === "Entrance" || shape.className === "Stairs") {
+                    shape.info.selectedPins.forEach((connectedShapeName) => {
+                        const connectedShape = floorShapes.find(s => s.info.name === connectedShapeName);
+                        if (
+                            connectedShape &&
+                            (connectedShape.className === "InfoPin" || connectedShape.className === "Entrance" || connectedShape.className === "Stairs")
+                        ) {
+                            if (!connectedShape.info.selectedPins.includes(shape.info.name)) {
+                                connectedShape.info.selectedPins.push(shape.info.name);
+                            }
+                        }
+                    });
+                }
+            });
+        });
+    }
+
+    drawConnection(node1Name, node2Name) {
+        const node1 = Object.values(this.store.floors).flat()
+            .find(shape => shape instanceof MapNode && shape.info.name === node1Name);
+        const node2 = Object.values(this.store.floors).flat()
+            .find(shape => shape instanceof MapNode && shape.info.name === node2Name);
+
+        console.log("NODE1: " + JSON.stringify(node1))
+        console.log("NODE2: " + JSON.stringify(node2));
+
+        if (node1 && node2) {
+            node1.connect(node2);
+            console.log("N1",node1.info.selectedPins,"N2",node2.info.selectedPins)
+        } else {
+            console.error("Cant find node1 or node 2.","Node1: " + node1,"Node2: " + node2);
+        }
+    }
+
+
+    removeConnection(from, to) {
+        let shapes = Object.values(this.store.floors).flat();
+
+        let node1 = ShapeQuery.findNodeByName(shapes, from);
+        let node2 = ShapeQuery.findNodeByName(shapes, to);
+
+        if(node1.floorNum === node2.floorNum)
+            node1.removeConnectionLine(node2);
+
+        //node1.removeConnection(node2);
+
+        Object.values(this.store.floors).flat().filter(s => s.info.name === from || s.info.name === to)
+            .forEach(s => {
+                if(s.info.name  === from){
+                    s.info.selectedPins = s.info.selectedPins.filter(pin =>  pin !== to);
+                } else {
+                    s.info.selectedPins = s.info.selectedPins.filter(pin =>  pin !== from);
+                }
+
+            });
+        console.log("Remove");
+    }
+
+    saveDetails() {
+        Object.values(this.store.floors).flat().forEach(shape => {
+            shape.saveShapeDetails();
+            console.log(shape.info);
+        });
+    }
+}
+
+/**
+ * A singleton instance that holds all the shapes for all the floors in the map builder.
+ * Every operation of adding, removing or updating drawn shapes should reference this instance.
+ */
+const instance = new ShapeRegistry();
+Object.freeze(instance);
+
+export default instance;
Index: imaps-frontend/src/scripts/util/addEventHandling.js
===================================================================
--- imaps-frontend/src/scripts/util/addEventHandling.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/util/addEventHandling.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,13 @@
+export const addEventHandling = (shape, map, action) => {
+    shape.on(action, () => {
+        const eventName = shape.eventName;
+        if (eventName) {
+            const data = {
+                room: shape,
+                map: map,
+            };
+            const event = new CustomEvent(eventName, { detail: data });
+            window.dispatchEvent(event);
+        }
+    });
+}
Index: imaps-frontend/src/scripts/util/parseMapData.js
===================================================================
--- imaps-frontend/src/scripts/util/parseMapData.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/util/parseMapData.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,28 @@
+import Factory from "./Factory.js";
+import shapeRegistry from "./ShapeRegistry.js";
+
+export default function parseMapData(data, predicate, rendered) {
+    if (data == null || data === "") return [];
+    const dsrData = JSON.parse(data);
+
+    console.log("VLEZE use")
+
+    let result = [];
+
+    dsrData.filter(predicate)
+        .forEach(s => {
+            console.log(s.attrs, "Sattrs pls")
+            s.attrs.position = {x: s.attrs.x, y: s.attrs.y}
+            const shape = rendered ? Factory.createRenderedShape(s.className, s.attrs) : Factory.createShape(s.className, s.attrs);
+
+            if (!rendered) {
+                shape.loadInfo(s.attrs);
+                shapeRegistry.add(shape)
+            }
+
+            result.push(shape)
+
+        })
+
+    return result;
+}
Index: imaps-frontend/src/scripts/util/queryShapes.js
===================================================================
--- imaps-frontend/src/scripts/util/queryShapes.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/util/queryShapes.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,8 @@
+export const queryShapeInfo = (map,type) => {
+    return map.shapes.filter(shape => shape.className === type).map(shape => shape.info);
+}
+
+export const queryRenderedShapes = (map,type) => {
+
+}
+
Index: imaps-frontend/src/scripts/util/triggerMapSave.js
===================================================================
--- imaps-frontend/src/scripts/util/triggerMapSave.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/util/triggerMapSave.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,21 @@
+let canSave = true;
+const mapSaveEvent = new CustomEvent("mapsave",{});
+const setCanSave = (value) => {
+    canSave = value;
+}
+/**
+ * Triggers a save event for the floor you are currently on with a debounce time of 3s;
+ * @example triggerMapSave() - will save the floor once, and after 3s again.
+ */
+const triggerMapSave = () => {
+    if(!canSave) return;
+
+    window.dispatchEvent(mapSaveEvent)
+    setCanSave(false);
+    setTimeout(() => {
+        setCanSave(true);
+        window.dispatchEvent(mapSaveEvent)
+    },2000)
+}
+
+export default triggerMapSave;
Index: imaps-frontend/src/scripts/util/triggerNavigate.js
===================================================================
--- imaps-frontend/src/scripts/util/triggerNavigate.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/util/triggerNavigate.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,14 @@
+const triggerNavigate = (nodes,idx,changeFloorTo,shape) => {
+    const event = new CustomEvent("navigate",{
+        detail: {
+            nodes: nodes,
+            offset: idx,
+            changeFloorTo: changeFloorTo,
+            shape:shape
+        }
+    })
+
+    window.dispatchEvent(event);
+}
+
+export default triggerNavigate;
Index: imaps-frontend/src/scripts/util/verifyToken.js
===================================================================
--- imaps-frontend/src/scripts/util/verifyToken.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/scripts/util/verifyToken.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,23 @@
+import HttpService from "../net/HttpService.js";
+import config from "../net/netconfig.js";
+
+export const verifyToken = async (setIsAuthenticated,setUsername,setLoading) => {
+    const token = localStorage.getItem("token");
+    const httpService = new HttpService();
+
+    try {
+        const response = await httpService.get(`${config.auth.verify}?token=${token}`);
+        if (response.username) {
+            setIsAuthenticated(true);
+            setUsername(response.username)
+            console.log("/verify resp: ",response.username);
+        } else {
+            setIsAuthenticated(false);
+            setLoading(false);
+        }
+    } catch (error) {
+        setIsAuthenticated(false);
+    } finally {
+        setLoading(false);
+    }
+}
Index: imaps-frontend/src/scripts/util/zoomStage.js
===================================================================
--- imaps-frontend/src/scripts/util/zoomStage.js	(revision d56544918790c0c3bc50f2f0a98c99f3d2988ccf)
+++ imaps-frontend/src/scripts/util/zoomStage.js	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -1,4 +1,4 @@
-export const zoomStage = (e,stage) => {
-    if (!e.evt.shiftKey) return;
+export const zoomStage = (e,stage,shift=false) => {
+    if (shift && !e.evt.shiftKey) return;
 
     e.evt.preventDefault();
