Skip to content

Commit 5f245d5

Browse files
committed
update route properly when room coordinates change
2 parents 6144db3 + ac86f7d commit 5f245d5

5 files changed

Lines changed: 489 additions & 594 deletions

File tree

backend/src/dbInterface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ export const queryBuildingsAndRooms =
111111
school
112112
usage
113113
capacity
114+
lat
115+
long
114116
}
115117
}
116118
}

frontend/components/Map.tsx

Lines changed: 30 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,18 @@
22
import "mapbox-gl/dist/mapbox-gl.css";
33

44
import { Building } from "@common/types";
5-
import mbxDirections from "@mapbox/mapbox-sdk/services/directions";
65
import Box from "@mui/material/Box";
76
import { DarkModeContext } from "app/clientLayout";
8-
import { useSearchParams } from "next/navigation";
97
import React, { useContext, useEffect, useRef, useState } from "react";
108
import {
11-
Layer,
129
LngLatBoundsLike,
1310
Map,
1411
MapRef,
1512
Marker,
1613
Source,
14+
Layer,
1715
} from "react-map-gl/mapbox";
1816
import { useDebounceValue } from "usehooks-ts";
19-
import BuildingDrawer from "views/BuildingDrawer";
2017

2118
import { MAPBOX_ACCESS_TOKEN } from "../config";
2219
import useBuildings from "../hooks/useBuildings";
@@ -69,12 +66,18 @@ if (!MAPBOX_ACCESS_TOKEN) {
6966
}
7067

7168
export const MapComponent = () => {
69+
// Use debounce to allow moving from marker to popup without popup hiding
70+
const [currentHover, setCurrentHover] = useState<Building | null>(null);
71+
const [debouncedCurrentHover] = useDebounceValue(currentHover, 50);
72+
const [routeGeoJSON, setRouteGeoJSON] = useState<any | null>(null);
73+
const [distances, setDistances] = useState<number[]>([]);
74+
const [roomIdToFocus, setRoomIdToFocus] = useState<string>("");
75+
76+
const mapRef = useRef<MapRef>(null);
77+
7278
const { buildings } = useBuildings();
7379
const { isDarkMode } = useContext(DarkModeContext);
7480
const { userLat, userLng } = useUserLocation();
75-
76-
const [roomIdToFocus, setRoomIdToFocus] = useState<string>("");
77-
7881
const { room } = useRoom(roomIdToFocus);
7982

8083
// TODO check if I need to only call this once? this is currently getting called every user change
@@ -87,32 +90,25 @@ export const MapComponent = () => {
8790
}, []);
8891

8992
useEffect(() => {
93+
console.log("HERE");
9094
if (!userLat || !userLng || !roomIdToFocus) return;
91-
if (!room) return;
92-
93-
// -33.917347,151.2286926
95+
console.log("test1");
96+
// Only set route once
97+
if (routeGeoJSON && routeGeoJSON.geometry) return;
98+
console.log("tes2");
99+
console.log(geometry);
94100

95101
setRouteGeoJSON({
96102
type: "Feature",
97103
properties: {},
98104
geometry,
99105
});
100-
}, [userLat, userLng, roomIdToFocus]);
101-
102-
const mapRef = useRef<MapRef>(null);
103-
104-
// Use debounce to allow moving from marker to popup without popup hiding
105-
const [currentHover, setCurrentHover] = useState<Building | null>(null);
106-
const [debouncedCurrentHover] = useDebounceValue(currentHover, 50);
107-
108-
const [routeGeoJSON, setRouteGeoJSON] = useState<any | null>(null);
106+
}, [userLat, userLng, roomIdToFocus, geometry]);
109107

110108
const style = isDarkMode
111109
? "mapbox://styles/bengodw/cmcimql2101qo01sp7dricgzq"
112110
: "mapbox://styles/bengodw/cmcimp1tz002p01rcfzbd8btn";
113111

114-
const [distances, setDistances] = useState<number[]>([]);
115-
116112
useEffect(() => {
117113
if (buildings && userLat && userLng && isInBounds(userLat, userLng)) {
118114
setDistances(
@@ -123,19 +119,6 @@ export const MapComponent = () => {
123119
}
124120
}, [buildings, userLat, userLng]);
125121

126-
// // TODO refactor to fetch room coordinates
127-
// const handleMarkerClick = async (building: Building) => {
128-
// if (!userLat || !userLng) return;
129-
130-
// const { geometry } = await useMapboxNavigation(userLat, userLng, building);
131-
132-
// setRouteGeoJSON({
133-
// type: "Feature",
134-
// properties: {},
135-
// geometry,
136-
// });
137-
// };
138-
139122
return (
140123
<div style={{ height: "100%", position: "relative" }}>
141124
<Map
@@ -167,16 +150,18 @@ export const MapComponent = () => {
167150
</Marker>
168151
)}
169152

170-
<RoomMapMarker
171-
roomId={roomIdToFocus}
172-
roomLocation={(lat, long) => {
173-
mapRef.current?.flyTo({
174-
center: [long, lat],
175-
zoom: 19.5,
176-
duration: 1000,
177-
});
178-
}}
179-
/>
153+
{roomIdToFocus && (
154+
<RoomMapMarker
155+
roomId={roomIdToFocus}
156+
roomLocation={(lat, long) => {
157+
mapRef.current?.flyTo({
158+
center: [long, lat],
159+
zoom: 19.5,
160+
duration: 1000,
161+
});
162+
}}
163+
/>
164+
)}
180165

181166
{routeGeoJSON && (
182167
<>
@@ -190,7 +175,7 @@ export const MapComponent = () => {
190175
"line-join": "round",
191176
}}
192177
paint={{
193-
"line-color": "#1DB954",
178+
"line-color": "#1976d2",
194179
"line-width": 4,
195180
}}
196181
/>

frontend/components/RoomMapMarker.tsx

Lines changed: 65 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,77 @@
11
"use client";
2-
import Image from "next/image";
3-
import { useEffect, useState } from "react";
4-
import { Marker } from "react-map-gl/mapbox";
52

6-
type RoomMarkersData = {
7-
[roomId: string]: [number, number];
8-
};
3+
import { alpha } from "@mui/material";
4+
import { Typography } from "@mui/material";
5+
import Box from "@mui/material/Box";
6+
import { useTheme } from "@mui/material/styles";
7+
import useRoom from "hooks/useRoom";
8+
import React, { useEffect, useRef } from "react";
9+
import { Marker } from "react-map-gl/mapbox";
910

10-
type RoomMarker = {
11-
id: string;
12-
lat: number;
13-
long: number;
14-
};
11+
interface RoomMapMarkerProps {
12+
roomId: string;
13+
roomLocation?: (lat: number, long: number) => void;
14+
}
1515

16-
const RoomMapMarker = ({
16+
const RoomMapMarker: React.FC<RoomMapMarkerProps> = ({
1717
roomId,
1818
roomLocation,
19-
}: {
20-
roomId?: string;
21-
roomLocation?: (lat: number, long: number) => void;
2219
}) => {
23-
// Changing data structure to {[id: string, lat: number, long: number]...}
24-
const [roomMarker, setRoomMarker] = useState<RoomMarker | null>(null);
20+
const { room } = useRoom(roomId);
21+
const hasFocusedRef = useRef(false);
22+
const theme = useTheme();
23+
2524
useEffect(() => {
26-
if (!roomId) return;
27-
fetch("/roommarkers.json")
28-
.then((res) => res.json())
29-
.then((markersData) => {
30-
const data = markersData as RoomMarkersData;
31-
const roomCoords = data[roomId];
32-
33-
if (roomCoords) {
34-
const [longitude, latitude] = roomCoords;
35-
const marker: RoomMarker = {
36-
id: roomId,
37-
lat: latitude,
38-
long: longitude,
39-
};
40-
setRoomMarker(marker);
41-
42-
if (roomLocation) {
43-
roomLocation(latitude, longitude);
44-
}
45-
}
46-
})
47-
.catch((err) => console.error("Failed to load room markers:", err));
48-
}, [roomId, roomLocation]);
49-
50-
if (!roomMarker) return null;
25+
if (!hasFocusedRef.current && room && roomLocation) {
26+
roomLocation(room.lat, room.long);
27+
hasFocusedRef.current = true;
28+
}
29+
}, [room, roomLocation]);
30+
31+
if (!room) return null;
32+
const blue = "#1976d2";
33+
5134
return (
52-
<Marker
53-
key={roomMarker.id}
54-
latitude={roomMarker.lat}
55-
longitude={roomMarker.long}
56-
anchor="bottom"
57-
>
58-
<Image src="/MapPin.png" alt="Room pin" width={30} height={30} />
35+
<Marker latitude={room.lat} longitude={room.long} anchor="bottom">
36+
<div
37+
style={{
38+
display: "flex",
39+
flexDirection: "column",
40+
alignItems: "center",
41+
position: "relative",
42+
}}
43+
>
44+
<Typography
45+
sx={{
46+
fontSize: 11,
47+
fontWeight: 500,
48+
textShadow:
49+
theme.palette.mode === "light"
50+
? "-.5px -.5px 1px #f2f2f2, .5px -.5px 1px #f2f2f2, -.5px .5px 1px #f2f2f2, .5px .5px 1px #f2f2f2"
51+
: "",
52+
color: theme.palette.text.primary,
53+
marginBottom: 1,
54+
userSelect: "none",
55+
}}
56+
>
57+
{room.name}
58+
</Typography>
59+
60+
<Box
61+
sx={(theme) => ({
62+
width: 18,
63+
height: 18,
64+
borderRadius: "50%",
65+
border: `5px solid ${blue}`,
66+
backgroundColor: "white",
67+
boxShadow: `0px 0px 6px 4px ${alpha(blue, 0.5)}`,
68+
position: "relative",
69+
"&:hover": {
70+
cursor: "pointer",
71+
},
72+
})}
73+
/>
74+
</div>
5975
</Marker>
6076
);
6177
};

frontend/hooks/useMapboxNavigation.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,21 @@ import { Room } from "@common/types";
44
import useSWRImmutable from "swr/immutable";
55

66
const fetchRoute = async (
7-
userLat: number,
8-
userLng: number,
9-
roomLat: number,
10-
roomLong: number
7+
userLat: number | undefined,
8+
userLng: number | undefined,
9+
roomLat: number | undefined,
10+
roomLong: number | undefined
1111
) => {
1212
if (!MAPBOX_ACCESS_TOKEN) {
1313
throw new Error("Missing Mapbox access token");
1414
}
1515

16+
if (!userLat || !userLng || !roomLat || !roomLong) {
17+
throw new Error("Invalid user or room coordinate");
18+
}
19+
1620
const directionsClient = mbxDirections({ accessToken: MAPBOX_ACCESS_TOKEN });
17-
console.log(userLat, userLng);
21+
console.log(userLat, userLng, roomLat, roomLong);
1822
try {
1923
const response = await directionsClient
2024
.getDirections({
@@ -27,10 +31,10 @@ const fetchRoute = async (
2731
})
2832
.send();
2933

34+
console.log("TEST", response.body.routes[0].geometry);
3035
return response.body.routes[0].geometry;
3136
// TODO proper typing here
3237
} catch (error: any) {
33-
console.log(error);
3438
throw error;
3539
}
3640
};
@@ -42,9 +46,13 @@ const useMapboxNavigation = (
4246
) => {
4347
/** TODO add proper types */
4448

45-
console.log("TEST", room);
4649
const { data, error } = useSWRImmutable(
47-
[userLat, userLng, room ? room.lat : null, room ? room.long : null],
50+
[
51+
userLat,
52+
userLng,
53+
room ? room.lat : undefined,
54+
room ? room.long : undefined,
55+
],
4856
fetchRoute
4957
);
5058

0 commit comments

Comments
 (0)