Index: imaps-frontend/src/pages/MapView/MapView.jsx
===================================================================
--- imaps-frontend/src/pages/MapView/MapView.jsx	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/pages/MapView/MapView.jsx	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,289 @@
+import {useNavigate, useParams, useSearchParams} from "react-router-dom";
+import React, {useContext, useEffect, useRef, useState} from "react";
+import {MapDisplay} from "../../scripts/main/MapDisplay.js";
+import styles from "./MapView.module.css";
+import SearchBar from "../../components/SearchBar/SearchBar.jsx";
+import FilterBar from "../../components/FilterBar/FilterBar.jsx";
+import Profile from "../../components/Profile/Profile.jsx";
+import RoomInfoPanel from "../../components/RoomInfoPanel/RoomInfoPanel.jsx";
+import HttpService from "../../scripts/net/HttpService.js";
+import floorIcon from "../../assets/floor_icon.png";
+import Logo from "../../components/Logo/Logo.jsx";
+import config from "../../scripts/net/netconfig.js";
+import parseMapData from "../../scripts/util/parseMapData.js";
+import ShapeRegistry from "../../scripts/util/ShapeRegistry.js";
+import {useAppContext} from "../../components/AppContext/AppContext.jsx";
+
+const MapView = ({isPrivate}) => {
+    const {mapName} = useParams();
+    const {username} = useAppContext();
+
+    const [mapLoaded, setMapLoaded] = useState(false);
+    const [app, setApp] = useState(null);
+    const [isPanelOpen, setIsPanelOpen] = useState(true);
+    const [selectedRoom, setSelectedRoom] = useState(null);
+    const [floors, setFloors] = useState([]); // ova trebit da sa objekti
+    const navigate = useNavigate();
+    const [shapes, setShapes] = useState([]);
+    const [searchParams, setSearchParams] = useSearchParams();
+    const [mainEntrance, setMainEntrance] = useState({});
+
+    const defaultNavObj = {
+        enabled: false,
+        nextFloor: 0,
+        nodes: [],
+        offset: 0
+    }
+
+    const [navNext, setNavNext] = useState(defaultNavObj)
+    const [roomTypes, setRoomTypes] = useState([]);
+
+    useEffect(() => {
+        const loadRoomTypes = async () => {
+            const httpService = new HttpService();
+            let roomTypes;
+            if (isPrivate) {
+                roomTypes = await httpService.get(`${config.room_types.display(true)}?mapName=${mapName}&username=${username}`)
+            } else {
+                roomTypes = await httpService.get(`${config.room_types.display(false)}?mapName=${mapName}`)
+            }
+
+            console.log("loaded ROOM TYPES: " + roomTypes)
+            setRoomTypes(roomTypes);
+        }
+        loadRoomTypes().then(resp => {
+            console.log("LOADED ROOM TYPES")
+        })
+    }, []);
+
+
+    useEffect(() => {
+        if (!searchParams.has("floor")) {
+            setSearchParams({floor: "0"}, {replace: true});
+        }
+    }, [setSearchParams, searchParams]);
+
+
+    useEffect(() => {
+
+
+        const floorNum = parseInt(searchParams.get("floor") || 0);
+        const appInstance = new MapDisplay("map", floorNum);
+
+        const load = async () => {
+            const httpService = new HttpService();
+
+            try {
+                let url;
+                if (isPrivate) {
+                    httpService.setAuthenticated();
+                    url = `${config.view_maps.load(true)}?mapName=${mapName}&username=${username}`
+                } else {
+                    url = `${config.view_maps.load(false)}?mapName=${mapName}`
+                }
+
+                return httpService.get(url);
+            } catch (e) {
+                throw new Error("Can't load map: " + e.message);
+            }
+        };
+
+        load()
+            .then(respFloors => {
+                let tlFloor = respFloors.filter(f => f.num === floorNum)[0];
+
+                let parsedShapes = [];
+
+                respFloors.forEach(flr => {
+                    console.log("FLR", flr)
+                    const parsed = parseMapData(flr.mapData, (shape => shape.className !== "InfoPin"), true)
+                    parsedShapes = [...parsedShapes, ...parsed];
+                })
+
+                setShapes(parsedShapes)
+
+                parsedShapes.forEach(shape => {
+                    console.info("PARSED Shapes: " + shape.info.name)
+                })
+
+                const mainEntrance = parsedShapes.find(shape => shape.info.isMainEntrance);
+                setMainEntrance(mainEntrance)
+
+                console.log("MAIN ENTRANCE: " + mainEntrance)
+
+
+                setFloors(respFloors);
+
+                appInstance.loadMapN(tlFloor?.mapData)
+                setApp(appInstance);
+                setMapLoaded(true);
+            })
+            .catch(reason => {
+                console.log("ERROR LOADING MAP VIEW: " + reason)
+            });
+
+
+    }, []);
+
+    //nova load, ne vo MapDisplay
+
+    //loso
+    useEffect(() => {
+        const openRoomInfoPanel = (e) => {
+            setSelectedRoom(e.detail.room);
+            setIsPanelOpen(true)
+            console.log("SHAPES REG", ShapeRegistry.getShapes().length)
+
+        }
+        window.addEventListener("openRoomInfoPanel", openRoomInfoPanel);
+
+        return () => window.removeEventListener("openRoomInfoPanel", openRoomInfoPanel);
+    }, [])
+
+    const handleDirectionsSubmit = (fromSearch = null, toSearch = null) => {
+
+        if (fromSearch === null && toSearch === null) {
+            return;
+        }
+        if (fromSearch === null || fromSearch === "") {
+            fromSearch = mainEntrance.info.name;
+        }
+        let shapeFrom = shapes.find(sh => sh.info.name === fromSearch)
+
+
+        if (shapeFrom.floorNum != searchParams.get("floor")) {
+            handleFloorChange(shapeFrom.floorNum);
+        }
+
+        const httpService = new HttpService();
+
+        if (isPrivate) httpService.setAuthenticated();
+
+        const fromEncoded = encodeURIComponent(fromSearch).trimEnd()
+        const toEncoded = encodeURIComponent(toSearch).trimEnd()
+
+        httpService.get(`${config.view_maps.navigate}?from=${fromEncoded}&to=${toEncoded}`).then(path => {
+            app.drawRouteNEW(path);
+        }).catch(reason => {
+            console.log("err", reason)
+        })
+    };
+
+    
+
+    const multiFloorNavigate = () => {
+        if (navNext && app) {
+            console.log("NAVNEXT F: " + navNext.nextFloor)
+            const f = navNext.nextFloor;
+            handleFloorChange(f)
+            setTimeout(() => {
+                app.drawRouteNEW(navNext.nodes, navNext.offset)
+            }, 50)
+            setNavNext(defaultNavObj)
+
+        }
+    }
+
+
+    useEffect(() => {
+
+        const handleNavigate = (event) => {
+            console.log("SHAPES NAV", shapes)
+
+            setNavNext({
+                enabled: true,
+                nextFloor: event.detail.changeFloorTo,
+                nodes: event.detail.nodes,
+                offset: event.detail.offset
+            })
+
+            console.log("ROUTE LAYER", app.routeLayer);
+        }
+
+        window.addEventListener("navigate", handleNavigate)
+        return () => {
+            window.removeEventListener("navigate", handleNavigate);
+        };
+
+    }, [app, mapLoaded]);
+
+    const handleFloorChange = (floorNum) => {
+        setSearchParams({floor: floorNum}, {replace: true});
+        const chFloor = floors.find(floor => floor.num === floorNum)
+
+        console.log("FLOOR NUM:", floorNum, "CHFLOOR:", chFloor)
+        app.clearRoute()
+        app.loadMapN(chFloor.mapData)
+        app.floorNum = floorNum;
+
+
+        console.log(`Floor changed to: ${floorNum}`);
+    };
+
+    const closePanel = () => {
+        setIsPanelOpen(false);
+        selectedRoom.unHighlight()
+    };
+
+
+    return (
+        <div id="main" className={styles.main}>
+            {navNext.enabled && (
+                <div className={styles.nextButtonContainer}>
+                    <button onClick={multiFloorNavigate} className={styles.nextButton}>
+                        NEXT FLOOR
+                    </button>
+                </div>
+            )}
+
+            <div id="map" className={styles.mapContainer}></div>
+
+            <RoomInfoPanel isOpen={isPanelOpen} onClose={closePanel} floor={searchParams.get("floor")}
+                           room={selectedRoom} handleDirectionsSubmit={handleDirectionsSubmit}/>
+            <div className={styles.toolbar}>
+                <div className={styles.toolbarContainer}>
+                    <div className={styles.logoContainer}>
+                        <Logo position="relative"/>
+                    </div>
+                    <h1 className={styles.mapTitle}>{mapName}</h1>
+                    {mapLoaded && app && (
+                        <div className={styles.searchFilterContainer}>
+                            <SearchBar
+                                map={app}
+                                handleDirectionsSubmit={handleDirectionsSubmit}
+                                setIsPanelOpen={setIsPanelOpen}
+                                setSelectedRoom={setSelectedRoom}
+                                availableShapes={shapes}
+                                handleFloorChange={handleFloorChange}
+                            />
+                            <FilterBar map={app} roomTypes={roomTypes}/>
+                        </div>
+                    )}
+                    <div className={styles.profileContainer}>
+                        <Profile position="relative"/>
+                    </div>
+                </div>
+            </div>
+
+            <div className={styles.floorSelectorContainer}>
+                <div className={styles.floorSelector}>
+                    <img src={floorIcon} alt="Floor Icon" className={styles.floorIcon}/>
+                    <select
+                        value={searchParams.get("floor")}
+                        onChange={(e) => handleFloorChange(parseInt(e.target.value, 10))}
+                        className={styles.floorDropdown}
+                    >
+                        {floors?.map((floor) => (
+                            <option key={floor.num} value={floor.num}>
+                                Floor {floor.num}
+                            </option>
+                        ))}
+                    </select>
+                </div>
+            </div>
+
+        </div>
+    );
+};
+
+export default MapView;
Index: imaps-frontend/src/pages/MapView/MapView.module.css
===================================================================
--- imaps-frontend/src/pages/MapView/MapView.module.css	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/pages/MapView/MapView.module.css	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,207 @@
+@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@700&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@700&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Raleway:wght@700&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Oswald:wght@700&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&display=swap");
+
+.main {
+  position: relative;
+  width: 100vw;
+  height: 100vh;
+  overflow: hidden;
+}
+
+.toolbar {
+  width: 100%;
+  padding: 10px 20px;
+  position: fixed;
+  top: 0;
+  z-index: 3;
+  background-color: rgba(255, 255, 255, 0.9);
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  display: flex;
+  align-items: center;
+}
+
+.toolbarContainer {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  max-width: 1200px;
+  margin: 0 auto;
+}
+
+.logoContainer {
+  display: flex;
+  align-items: center;
+  flex-shrink: 0;
+}
+
+.mapTitle {
+  font-size: 1.5rem;
+  font-weight: bold;
+  text-transform: uppercase;
+  color: #333333;
+  margin: 0 20px;
+  flex-grow: 1;
+  text-align: center;
+  font-family: "Oswald", sans-serif;
+}
+
+.searchFilterContainer {
+  flex-grow: 3;
+  display: flex;
+  align-items: center;
+  gap: 150px;
+  justify-content: flex-start;
+  padding: 0 10px;
+  overflow-x: auto;
+  scrollbar-width: thin;
+  scrollbar-color: #d6d6d6 transparent;
+}
+
+.searchFilterContainer::-webkit-scrollbar {
+  height: 6px;
+}
+
+.searchFilterContainer::-webkit-scrollbar-thumb {
+  background-color: #d6d6d6;
+  border-radius: 10px;
+}
+
+.profileContainer {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  flex-shrink: 0;
+}
+
+
+.mapTitle {
+  font-size: 1.5rem;
+  font-weight: bold;
+  text-transform: uppercase;
+  color: #333333;
+  margin: 0 20px;
+  flex-grow: 1;
+  text-align: center;
+  font-family: "Oswald", sans-serif;
+}
+
+.searchFilterContainer {
+  display: flex;
+  align-items: center;
+  gap: 20px;
+}
+
+.profileContainer {
+  display: flex;
+  align-items: center;
+}
+
+.mapContainer {
+  position: relative;
+  top: 0px;
+  left: 0;
+  width: 100vw;
+  height: 100vh;
+  z-index: 1;
+  background-color: #F2F2F2;
+}
+
+.mapControlsContainer {
+  position: absolute;
+  bottom: 20px;
+  right: 20px;
+  z-index: 1;
+}
+
+.nextButtonContainer {
+  position: absolute;
+  bottom: 20%;
+  left: 50%;
+  transform: translateX(-50%);
+  z-index: 5;
+}
+
+.nextButton {
+  font-size: 1.5em;
+  font-weight: bold;
+  padding: 15px 30px;
+  background-color: #007bff;
+  color: #fff;
+  border: none;
+  border-radius: 50px;
+  box-shadow: 0 4px 15px rgba(0, 123, 255, 0.75);
+  cursor: pointer;
+  animation: pulse 2s infinite;
+  transition: transform 0.2s ease-in-out;
+}
+
+.nextButton:hover {
+  transform: scale(1.1);
+  background-color: #0056b3;
+}
+
+@keyframes pulse {
+  0% {
+    box-shadow: 0 0 15px rgba(0, 123, 255, 0.5);
+  }
+  50% {
+    box-shadow: 0 0 30px rgba(0, 123, 255, 0.8);
+  }
+  100% {
+    box-shadow: 0 0 15px rgba(0, 123, 255, 0.5);
+  }
+}
+.floorSelectorContainer {
+  position: fixed;
+  bottom: 50px;
+  left: 50%;
+  transform: translateX(-50%);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 10;
+  padding: 10px;
+  background-color: rgba(255, 255, 255, 0.9);
+  border-radius: 20px;
+  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2);
+}
+
+.floorSelector {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.floorIcon {
+  width: 40px;
+  height: 40px;
+}
+
+.floorDropdown {
+  font-size: 1.5em;
+  padding: 10px 20px;
+  border-radius: 10px;
+  border: 2px solid #007bff;
+  outline: none;
+  background-color: #f9f9f9;
+  color: #333;
+  transition: all 0.3s ease-in-out;
+  cursor: pointer;
+}
+
+.floorDropdown:hover,
+.floorDropdown:focus {
+  border-color: #0056b3;
+  background-color: #e6f7ff;
+}
+
+.floorDropdown option {
+  font-size: 1.2em;
+  padding: 5px;
+  background-color: #fff;
+  color: #333;
+}
Index: imaps-frontend/src/pages/MapView/useMapViewHook.jsx
===================================================================
--- imaps-frontend/src/pages/MapView/useMapViewHook.jsx	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
+++ imaps-frontend/src/pages/MapView/useMapViewHook.jsx	(revision 0c6b92add4cfaedcb91bcd37b45849f142f7d152)
@@ -0,0 +1,21 @@
+//
+// function useMapViewHook() {
+//   const { mapName } = useParams();
+//   const { username } = useContext(AuthContext);
+//
+//   const [mapLoaded, setMapLoaded] = useState(false);
+//   const [app, setApp] = useState(null);
+//   const [isPanelOpen, setIsPanelOpen] = useState(true);
+//   const [floors, setFloors] = useState([]);
+//   const navigate = useNavigate();
+//
+//   const [searchParams, setSearchParams] = useSearchParams();
+//
+//   return {
+//     mapName,
+//     username,
+//     mapLoaded
+//   }
+// }
+//
+// export default useMapViewHook;
