diff --git a/backend/package-lock.json b/backend/package-lock.json index fb6e6654a..39747f4c8 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -71,6 +71,7 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -1756,6 +1757,7 @@ "integrity": "sha512-5vtOqGQr4NJKeEzV441FcOi2MeG9UTWq9LqVLGneDdu4vlX17H8kQ2PA2UmNwCUGPVDj4oBjNhS7ReVEIWJJrg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.18.0" } @@ -1869,6 +1871,7 @@ "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/types": "8.60.1", @@ -2436,6 +2439,7 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2784,6 +2788,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -3255,6 +3260,7 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -3516,6 +3522,7 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4351,6 +4358,7 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.1.tgz", "integrity": "sha512-cQOsSMS/IrDz82PVyRDvf/Q1F/bRbBVjJlh+xYOkI1qw2bWRvWGiWc+m2O0d6l4Bt1fyY+8kzJ8JFWGJqNeDBg==", "license": "MIT", + "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -4760,6 +4768,7 @@ "integrity": "sha512-Yi1jqNC/Oq0N4hBgNH/YvBpP1P57QqundgytzYqy3yqAa7NZPNjSoi4SGbRAXDMdBzNE6xBCi5U7RgfrvMEUVQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "30.4.2", "@jest/types": "30.4.1", @@ -7162,6 +7171,38 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -7298,6 +7339,7 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -7464,6 +7506,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/frontend/__tests__/BuildingDrawer.test.tsx b/frontend/__tests__/BuildingDrawer.test.tsx index 5b051036e..363a1f7a4 100644 --- a/frontend/__tests__/BuildingDrawer.test.tsx +++ b/frontend/__tests__/BuildingDrawer.test.tsx @@ -14,6 +14,13 @@ jest.mock("@mui/material", () => ({ ...jest.requireActual("@mui/material"), useMediaQuery: jest.fn().mockReturnValue(false), })); +jest.mock("next/navigation", () => ({ + ...jest.requireActual("next/navigation"), + useRouter: jest.fn().mockReturnValue({ + push: jest.fn(), + replace: jest.fn(), + }), +})); describe("BuildingDrawer", () => { it("Building Drawer shows close button", () => { diff --git a/frontend/app/map/page.tsx b/frontend/app/map/page.tsx index 517d2b050..79381867d 100644 --- a/frontend/app/map/page.tsx +++ b/frontend/app/map/page.tsx @@ -1,7 +1,13 @@ "use client"; +import { Suspense } from "react"; + import { Map } from "../../components/Map"; export default function Page() { - return ; + return ( + + + + ); } diff --git a/frontend/app/room/[room]/page.tsx b/frontend/app/room/[room]/page.tsx index f8f020488..df1cc5f51 100644 --- a/frontend/app/room/[room]/page.tsx +++ b/frontend/app/room/[room]/page.tsx @@ -29,10 +29,12 @@ import BookingCalendar from "../../../components/BookingCalendar"; import FeedbackButton from "../../../components/FeedbackButton"; import LoadingCircle from "../../../components/LoadingCircle"; import RoomBackButton from "../../../components/RoomBackButton"; +import ViewOnMapButton from "../../../components/ViewOnMapButton"; import useBookings from "../../../hooks/useBookings"; import useBuilding from "../../../hooks/useBuilding"; import useRoom from "../../../hooks/useRoom"; import room_photos from "../../../public/room-photos.json"; +import { getBuildingIdFromRoomId } from "../../../utils/utils"; const adjustDateIfMidnight = (inputDate: Date): Date => { // Check if the time is midnight (00:00:00) @@ -115,6 +117,7 @@ const RoomPageHeader: React.FC<{ room: Room; buildingName: string }> = ({ : "This room is managed externally by its associated school. Please contact the school to request a booking"; const ratings = useRoomRatings(room.id); + const buildingId = getBuildingIdFromRoomId(room.id); const ratingValue = (() => { // round rating to nearest .5 if a rating exists if (!ratings || !ratings.data) return 0; @@ -180,11 +183,17 @@ const RoomPageHeader: React.FC<{ room: Room; buildingName: string }> = ({ {room.name} - + + + + diff --git a/frontend/components/Map.tsx b/frontend/components/Map.tsx index c661d8312..f1032f4fe 100644 --- a/frontend/components/Map.tsx +++ b/frontend/components/Map.tsx @@ -1,4 +1,5 @@ import { Building } from "@common/types"; +import useBuilding from "@frontend/hooks/useBuilding"; import Box from "@mui/material/Box"; import { GoogleMap, @@ -7,13 +8,16 @@ import { useJsApiLoader, } from "@react-google-maps/api"; import { DarkModeContext } from "app/clientLayout"; -import React, { useContext, useMemo, useState } from "react"; +import { useSearchParams } from "next/navigation"; +import React, { useContext, useEffect, useMemo, useState } from "react"; import { useDebounceValue } from "usehooks-ts"; import BuildingDrawer from "views/BuildingDrawer"; import { GOOGLE_API_KEY } from "../config"; import useBuildings from "../hooks/useBuildings"; import useUserLocation from "../hooks/useUserLocation"; +import { setCurrentBuilding } from "../redux/currentBuildingSlice"; +import { useDispatch } from "../redux/hooks"; import calculateDistance from "../utils/calculateDistance"; import getMapType from "../utils/getMapType"; import MapMarker from "./MapMarker"; @@ -55,7 +59,7 @@ export const Map = () => { // Fetch data const { buildings } = useBuildings(); const { isDarkMode } = useContext(DarkModeContext); - + const dispatch = useDispatch(); // Use debounce to allow moving from marker to popup without popup hiding const [currentHover, setCurrentHover] = useState(null); const [debouncedCurrentHover] = useDebounceValue(currentHover, 50); @@ -70,15 +74,25 @@ export const Map = () => { }); const distances = useMemo(() => { - if (!(buildings && userLat && userLng && isInBounds(userLat, userLng))) { - return []; + if (buildings && userLat && userLng && isInBounds(userLat, userLng)) { + return buildings.map((building) => + calculateDistance(userLat, userLng, building.lat, building.long) + ); } - - return buildings.map((building) => - calculateDistance(userLat, userLng, building.lat, building.long) - ); + return []; }, [buildings, userLat, userLng]); + //set current building to search param query - THIS IS WHERE OTHER QUERIES CAN GO + const searchParams = useSearchParams(); + const buildingId = searchParams.get("building"); + const { building } = useBuilding(buildingId || ""); + + useEffect(() => { + if (building) { + dispatch(setCurrentBuilding(building || null)); + } + }, [building, dispatch]); + const mapOptions = useMemo( () => ({ clickableIcons: false, diff --git a/frontend/components/MapMarker.tsx b/frontend/components/MapMarker.tsx index e6824533b..608558047 100644 --- a/frontend/components/MapMarker.tsx +++ b/frontend/components/MapMarker.tsx @@ -6,6 +6,7 @@ import { Typography } from "@mui/material"; import Box, { BoxProps } from "@mui/material/Box"; import { styled, useTheme } from "@mui/material/styles"; import Image, { ImageProps } from "next/image"; +import { useRouter, useSearchParams } from "next/navigation"; import React from "react"; import useBuilding from "../hooks/useBuilding"; @@ -69,20 +70,27 @@ const MapMarker: React.FC<{ const { building } = useBuilding(buildingId); const { status: liveStatus } = useBuildingStatus(buildingId); const theme = useTheme(); - + const router = useRouter(); // This one uses stale data so markers don't disappear const status: BuildingStatus | undefined = liveStatus; const freerooms = getNumFreerooms(status); const totalRooms = getTotalRooms(status); + const searchParams = useSearchParams(); + const params = new URLSearchParams(searchParams); const dispatch = useDispatch(); const currentBuilding = useSelector(selectCurrentBuilding); const isCurrentBuilding = currentBuilding?.id === building?.id; const showPopup = currentHover?.id === building?.id; - - const [appearLeft, setAppearLeft] = React.useState(false); const [appearAbove, setAppearAbove] = React.useState(false); + const [appearLeft, setAppearLeft] = React.useState(false); + + const handleSelectBuilding = () => { + dispatch(setCurrentBuilding(building || null)); + params.set("building", buildingId); // Add or update the 'query' param + router.push(`/map?${params.toString()}`); + }; const colour = freerooms >= 5 ? "#66bb6a" : freerooms !== 0 ? "#ffa726" : "#f44336"; @@ -121,6 +129,8 @@ const MapMarker: React.FC<{ sx={{ fontSize: 11, fontWeight: 500, + translate: isCurrentBuilding ? "0px -10px" : "0px 0px", + transition: "all 0.2s ease-in-out", textShadow: theme.palette.mode === "light" ? "-.5px -.5px 1px #f2f2f2, .5px -.5px 1px #f2f2f2, -.5px .5px 1px #f2f2f2, .5px .5px 1px #f2f2f2" @@ -137,6 +147,8 @@ const MapMarker: React.FC<{ borderRadius: "50%", border: isCurrentBuilding ? `5px solid ${colour}` : "4px solid white", backgroundColor: isCurrentBuilding ? "white" : colour, + scale: isCurrentBuilding ? 2 : 1, + transition: "all 0.2s ease-in-out", boxShadow: isCurrentBuilding ? `0px 0px 6px 4px ${alpha(colour, 0.5)}` : "", @@ -145,7 +157,7 @@ const MapMarker: React.FC<{ cursor: "pointer", }, }} - onClick={() => dispatch(setCurrentBuilding(building))} + onClick={() => handleSelectBuilding()} />
diff --git a/frontend/components/ViewOnMapButton.tsx b/frontend/components/ViewOnMapButton.tsx new file mode 100644 index 000000000..d31b70a85 --- /dev/null +++ b/frontend/components/ViewOnMapButton.tsx @@ -0,0 +1,51 @@ +import useBuilding from "@frontend/hooks/useBuilding"; +import { useTheme } from "@mui/material"; +import Typography from "@mui/material/Typography"; +import { useRouter } from "next/navigation"; +import React from "react"; + +import { setCurrentBuilding } from "../redux/currentBuildingSlice"; +import { useDispatch } from "../redux/hooks"; +import Button from "./Button"; + +const ViewOnMapButton: React.FC<{ + buildingId: string; + variant?: "default" | "full-width"; +}> = ({ buildingId, variant = "default" }) => { + const theme = useTheme(); + + const dispatch = useDispatch(); + const router = useRouter(); + const { building } = useBuilding(buildingId); + + const handleMapRedirect = (buildingId: string) => { + dispatch(setCurrentBuilding(building || null)); + router.push(`/map?building=${buildingId}`); + }; + + return ( + + ); +}; + +export default ViewOnMapButton; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 045559f11..481520ac1 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -233,6 +233,7 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -808,6 +809,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -831,6 +833,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -842,6 +845,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" @@ -853,6 +857,7 @@ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -932,6 +937,7 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -975,6 +981,7 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -1349,9 +1356,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1368,9 +1372,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1387,9 +1388,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1406,9 +1404,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1425,9 +1420,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1444,9 +1436,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1463,9 +1452,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1482,9 +1468,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1501,9 +1484,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1526,9 +1506,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1551,9 +1528,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1576,9 +1550,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1601,9 +1572,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1626,9 +1594,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1651,9 +1616,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1676,9 +1638,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -2390,6 +2349,7 @@ "resolved": "https://registry.npmjs.org/@mui/material/-/material-9.0.1.tgz", "integrity": "sha512-voyCpeUxcSWLN7KPZuq0pGCIt726T9K6kiVM3XUcywZDAlZSarLHaUxJVQpospbjjOzN53hwyjo8s6KoWl6utw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.29.2", "@mui/core-downloads-tracker": "^9.0.1", @@ -2500,6 +2460,7 @@ "resolved": "https://registry.npmjs.org/@mui/system/-/system-9.0.1.tgz", "integrity": "sha512-WvlioaLxk6ewUIOfh0StxUvOPDS1mCfzaulcudsL1brZNXuh0N9FMk7RpH7ImJKjEz412SEy/V/yvqmtxbqxCQ==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.29.2", "@mui/private-theming": "^9.0.1", @@ -2774,9 +2735,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2793,9 +2751,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2812,9 +2767,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2831,9 +2783,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3909,8 +3858,7 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -4089,6 +4037,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -4110,6 +4059,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.16.tgz", "integrity": "sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -4223,6 +4173,7 @@ "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/types": "8.60.1", @@ -4586,9 +4537,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4603,9 +4551,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4620,9 +4565,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4637,9 +4579,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4654,9 +4593,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4671,9 +4607,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4688,9 +4621,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4705,9 +4635,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4722,9 +4649,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4739,9 +4663,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4828,6 +4749,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5450,6 +5372,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -5933,6 +5856,7 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/kossnocorp" @@ -5951,7 +5875,8 @@ "version": "1.11.21", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/debug": { "version": "4.4.3", @@ -6109,8 +6034,7 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/dom-helpers": { "version": "6.0.1", @@ -6393,6 +6317,7 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -9371,6 +9296,7 @@ "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "cssstyle": "^4.2.1", "data-urls": "^5.0.0", @@ -9650,6 +9576,7 @@ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" } @@ -9660,7 +9587,6 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -9857,6 +9783,7 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "license": "MIT", + "peer": true, "engines": { "node": "*" } @@ -10411,6 +10338,7 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -10567,7 +10495,6 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -10583,7 +10510,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -10596,8 +10522,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/prop-types": { "version": "15.8.1", @@ -10678,6 +10603,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -10715,6 +10641,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -10795,6 +10722,7 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz", "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", "license": "MIT", + "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -10857,7 +10785,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -11992,6 +11921,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -12191,6 +12121,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12821,6 +12752,7 @@ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/frontend/utils/utils.ts b/frontend/utils/utils.ts index 3f785b5dd..ce226b3b2 100644 --- a/frontend/utils/utils.ts +++ b/frontend/utils/utils.ts @@ -18,3 +18,8 @@ export const getTotalRooms = ( return Object.values(buildingStatus.roomStatuses).length; }; + +//gets the building id from a room id +export const getBuildingIdFromRoomId = (roomId: string): string => { + return roomId.split("-").slice(0, 2).join("-"); +}; diff --git a/frontend/views/BuildingDrawer.tsx b/frontend/views/BuildingDrawer.tsx index 8a789e07e..47c810add 100644 --- a/frontend/views/BuildingDrawer.tsx +++ b/frontend/views/BuildingDrawer.tsx @@ -1,3 +1,4 @@ +import ViewOnMapButton from "@frontend/components/ViewOnMapButton"; import CloseIcon from "@mui/icons-material/Close"; import { Slide, Typography, useMediaQuery } from "@mui/material"; import Box, { BoxProps } from "@mui/material/Box"; @@ -134,6 +135,7 @@ const BuildingDrawer: React.FC = () => { style={{ objectFit: "cover" }} priority={true} /> +