Skip to content

Commit a6319f8

Browse files
authored
Merge pull request #14 from JMarques1196/dev
Feat: Added the Map with a placeholder track
2 parents 2333199 + e2fe58e commit a6319f8

File tree

7 files changed

+170
-0
lines changed

7 files changed

+170
-0
lines changed

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<link rel="icon" href="/favicon.ico" />
66
<link rel="preconnect" href="https://fonts.googleapis.com">
77
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
8+
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
89
<link href="https://fonts.googleapis.com/css2?family=Big+Shoulders+Stencil:opsz,[email protected],100..900&family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap" rel="stylesheet">
910
<meta name="viewport" content="width=device-width, initial-scale=1" />
1011
<meta name="theme-color" content="#000000" />

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"@testing-library/user-event": "^14.6.0",
5858
"@types/jest": "^29.5.14",
5959
"@types/leaflet": "^1.9.18",
60+
"@types/leaflet-gpx": "^1.3.7",
6061
"@types/node": "^22.10.2",
6162
"@types/react": "^19.0.7",
6263
"@types/react-dom": "^19.0.3",

src/components/Map/map.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.map-container{
2+
width: 500px;
3+
height: 300px;
4+
}

src/components/Map/map.tsx

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,94 @@
11
//Component to display gpx tracks
2+
import React, { useEffect, useRef } from "react";
3+
import L from "leaflet";
4+
import "./map.css";
5+
6+
delete (L.Icon.Default.prototype as any)._getIconUrl;
7+
L.Icon.Default.mergeOptions({
8+
iconRetinaUrl:
9+
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png",
10+
iconUrl:
11+
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png",
12+
shadowUrl:
13+
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png",
14+
});
15+
16+
interface TrackPoint {
17+
lat: number;
18+
lng: number;
19+
}
20+
21+
const Map: React.FC = () => {
22+
const mapRef = useRef<HTMLDivElement>(null);
23+
const mapInstanceRef = useRef<L.Map | null>(null);
24+
25+
// Placeholder track, to be replace with data from Firebase
26+
const trackData: TrackPoint[] = [
27+
{ lat: 41.1579, lng: -8.6291 }, // Porto, Portugal
28+
{ lat: 41.1621, lng: -8.622 },
29+
{ lat: 41.165, lng: -8.615 },
30+
{ lat: 41.168, lng: -8.608 },
31+
{ lat: 41.171, lng: -8.601 },
32+
{ lat: 41.174, lng: -8.594 },
33+
{ lat: 41.177, lng: -8.587 },
34+
{ lat: 41.18, lng: -8.58 },
35+
];
36+
37+
useEffect(() => {
38+
if (!mapRef.current) return;
39+
40+
// Initialize the map
41+
const map = L.map(mapRef.current).setView([41.1579, -8.6291], 13);
42+
mapInstanceRef.current = map;
43+
44+
// Add tile layer
45+
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
46+
attribution:
47+
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
48+
}).addTo(map);
49+
50+
// Create polyline for the track
51+
const polyline = L.polyline(
52+
trackData.map((point) => [point.lat, point.lng]),
53+
{
54+
color: "#3388ff",
55+
weight: 4,
56+
opacity: 0.8,
57+
}
58+
).addTo(map);
59+
60+
// Add markers for start and end points
61+
const startMarker = L.marker([trackData[0].lat, trackData[0].lng])
62+
.addTo(map)
63+
.bindPopup("Start Point");
64+
65+
const endMarker = L.marker([
66+
trackData[trackData.length - 1].lat,
67+
trackData[trackData.length - 1].lng,
68+
])
69+
.addTo(map)
70+
.bindPopup("End Point");
71+
72+
// Fit map to track bounds
73+
map.fitBounds(polyline.getBounds(), { padding: [20, 20] });
74+
75+
// Cleanup function
76+
return () => {
77+
if (mapInstanceRef.current) {
78+
mapInstanceRef.current.remove();
79+
mapInstanceRef.current = null;
80+
}
81+
};
82+
}, []);
83+
84+
return (
85+
<div className="map-container">
86+
<div className="">
87+
<h1 className="">Track Map</h1>
88+
</div>
89+
<div ref={mapRef} className="" style={{ height: "500px" }} />
90+
</div>
91+
);
92+
};
93+
94+
export default Map;

src/components/Menu/activity-menu.test.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,62 @@ global.ResizeObserver = vi.fn().mockImplementation(() => {
1313
unobserve: vi.fn(),
1414
};
1515
});
16+
// Leaflet
17+
vi.mock("leaflet", () => ({
18+
default: {
19+
map: vi.fn(() => ({
20+
setView: vi.fn().mockReturnThis(),
21+
remove: vi.fn(),
22+
fitBounds: vi.fn(),
23+
addTo: vi.fn().mockReturnThis(),
24+
})),
25+
tileLayer: vi.fn(() => ({
26+
addTo: vi.fn().mockReturnThis(),
27+
})),
28+
polyline: vi.fn(() => ({
29+
addTo: vi.fn().mockReturnThis(),
30+
getBounds: vi.fn(() => [[0, 0], [1, 1]]),
31+
})),
32+
marker: vi.fn(() => ({
33+
addTo: vi.fn().mockReturnThis(),
34+
bindPopup: vi.fn().mockReturnThis(),
35+
})),
36+
Icon: {
37+
Default: {
38+
prototype: {
39+
_getIconUrl: vi.fn(),
40+
},
41+
mergeOptions: vi.fn(),
42+
},
43+
},
44+
},
45+
map: vi.fn(() => ({
46+
setView: vi.fn().mockReturnThis(),
47+
remove: vi.fn(),
48+
fitBounds: vi.fn(),
49+
addTo: vi.fn().mockReturnThis(),
50+
})),
51+
tileLayer: vi.fn(() => ({
52+
addTo: vi.fn().mockReturnThis(),
53+
})),
54+
polyline: vi.fn(() => ({
55+
addTo: vi.fn().mockReturnThis(),
56+
getBounds: vi.fn(() => [[0, 0], [1, 1]]),
57+
})),
58+
marker: vi.fn(() => ({
59+
addTo: vi.fn().mockReturnThis(),
60+
bindPopup: vi.fn().mockReturnThis(),
61+
})),
62+
Icon: {
63+
Default: {
64+
prototype: {
65+
_getIconUrl: vi.fn(),
66+
},
67+
mergeOptions: vi.fn(),
68+
},
69+
},
70+
}));
71+
1672
// Firebase
1773
vi.mock("firebase/firestore", () => ({
1874
collection: vi.fn(),

src/components/Menu/activity-menu.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useState, useEffect } from "react";
22
import "./activity.css";
33
import Graph from "../Graph/graph";
4+
import Map from "../Map/map";
45
import { collection, getDocs, QuerySnapshot } from "firebase/firestore";
56
import { db } from "src/firebase.js";
67
import { seedDatabase } from "src/helper/seed";
@@ -94,6 +95,9 @@ const Menu = () => {
9495
</div>
9596
<Graph name={metric} data={filteredContent} />
9697
</section>
98+
<section className="map">
99+
<Map />
100+
</section>
97101
</>
98102
);
99103
};

0 commit comments

Comments
 (0)