From 07889408994f2289b7c37e160d118a19ae4c8fb9 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 1 Mar 2025 22:37:11 +0000 Subject: [PATCH] [server]: Plot some basic train data --- frontend/attribution.txt | 1 + frontend/index.html | 2 +- frontend/package-lock.json | 104 ++++++++++++++--- frontend/package.json | 6 +- frontend/src/App.jsx | 167 +++++++++++++++++---------- frontend/src/components/TabTitle.jsx | 14 --- 6 files changed, 206 insertions(+), 88 deletions(-) delete mode 100644 frontend/src/components/TabTitle.jsx diff --git a/frontend/attribution.txt b/frontend/attribution.txt index 29383bd..f1243c3 100644 --- a/frontend/attribution.txt +++ b/frontend/attribution.txt @@ -3,3 +3,4 @@ Bus Station: https://www.flaticon.com/authors/boris-farias Train Station: https://www.flaticon.com/authors/nawicon Bus: https://www.flaticon.com/authors/hilmy-abiyyu-a Train: https://www.flaticon.com/authors/google +DART: https://www.freepik.com/ diff --git a/frontend/index.html b/frontend/index.html index 86fa92c..3d3b7dd 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,7 +3,7 @@ - Vite + React + Iompar
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 66920f7..d071824 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,11 +11,13 @@ "@tailwindcss/vite": "^4.0.9", "autoprefixer": "^10.4.20", "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", "postcss": "^8.5.3", - "react": "^19.0.0-rc.1", - "react-dom": "^19.0.0-rc.1", + "react": "^19.0.0", + "react-dom": "^19.0.0", "react-helmet": "^6.1.0", "react-leaflet": "^5.0.0-rc.2", + "react-leaflet-markercluster": "^5.0.0-rc.0", "tailwindcss": "^4.0.9" }, "devDependencies": { @@ -38,6 +40,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -54,6 +57,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -70,6 +74,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -86,6 +91,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -102,6 +108,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -118,6 +125,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -134,6 +142,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -150,6 +159,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -166,6 +176,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -182,6 +193,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -198,6 +210,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -214,6 +227,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -230,6 +244,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -246,6 +261,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -262,6 +278,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -278,6 +295,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -294,6 +312,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -310,6 +329,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -326,6 +346,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -342,6 +363,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -358,6 +380,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -374,6 +397,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -390,6 +414,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -406,6 +431,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -422,6 +448,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -638,6 +665,17 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@react-leaflet/core": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", + "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", + "license": "Hippocratic-2.1", + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.34.8", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", @@ -645,6 +683,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -658,6 +697,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -671,6 +711,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -684,6 +725,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -697,6 +739,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -710,6 +753,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -723,6 +767,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -736,6 +781,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -749,6 +795,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -762,6 +809,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -775,6 +823,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -788,6 +837,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -801,6 +851,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -814,6 +865,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -827,6 +879,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -840,6 +893,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -853,6 +907,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -866,6 +921,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -879,6 +935,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1339,6 +1396,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, "license": "MIT" }, "node_modules/@types/json-schema": { @@ -2191,6 +2249,7 @@ "version": "0.25.0", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -2564,6 +2623,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -3361,6 +3421,15 @@ "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", "license": "BSD-2-Clause" }, + "node_modules/leaflet.markercluster": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz", + "integrity": "sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==", + "license": "MIT", + "peerDependencies": { + "leaflet": "^1.3.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4061,12 +4130,12 @@ "license": "MIT" }, "node_modules/react-leaflet": { - "version": "5.0.0-rc.2", - "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0-rc.2.tgz", - "integrity": "sha512-1xQGYG9mEIW+nfkQhqgHImwUuB1UDlnzYFSzv6PrBFDBeYrFmv0BbpwpNAFdJg/UQ2yz5UZSL7ZwlUxjwb8MZw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0.tgz", + "integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==", "license": "Hippocratic-2.1", "dependencies": { - "@react-leaflet/core": "^3.0.0-rc.2" + "@react-leaflet/core": "^3.0.0" }, "peerDependencies": { "leaflet": "^1.9.0", @@ -4074,15 +4143,22 @@ "react-dom": "^19.0.0" } }, - "node_modules/react-leaflet/node_modules/@react-leaflet/core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", - "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", - "license": "Hippocratic-2.1", + "node_modules/react-leaflet-markercluster": { + "version": "5.0.0-rc.0", + "resolved": "https://registry.npmjs.org/react-leaflet-markercluster/-/react-leaflet-markercluster-5.0.0-rc.0.tgz", + "integrity": "sha512-jWa4bPD5LfLV3Lid1RWgl+yKUuQtnqeYtJzzLb/fiRjvX+rtwzY8pMoUFuygqyxNrWxMTQlWKBHxkpI7Sxvu4Q==", + "license": "MIT", + "dependencies": { + "@react-leaflet/core": "^3.0.0", + "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", + "react-leaflet": "^5.0.0" + }, "peerDependencies": { - "leaflet": "^1.9.0", + "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-leaflet": "^5.0.0" } }, "node_modules/reflect.getprototypeof": { @@ -4161,6 +4237,7 @@ "version": "4.34.8", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.6" @@ -4729,6 +4806,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz", "integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", + "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", diff --git a/frontend/package.json b/frontend/package.json index 8872d22..a305a22 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,11 +13,13 @@ "@tailwindcss/vite": "^4.0.9", "autoprefixer": "^10.4.20", "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", "postcss": "^8.5.3", - "react": "^19.0.0-rc.1", - "react-dom": "^19.0.0-rc.1", + "react": "^19.0.0", + "react-dom": "^19.0.0", "react-helmet": "^6.1.0", "react-leaflet": "^5.0.0-rc.2", + "react-leaflet-markercluster": "^5.0.0-rc.0", "tailwindcss": "^4.0.9" }, "devDependencies": { diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 4855e3c..8065e77 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,82 +1,133 @@ -// App.jsx -import React from "react"; +import React, { useState } from "react"; import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet"; import "leaflet/dist/leaflet.css"; -import L from "leaflet"; -import { Icon } from "leaflet"; +import L, { Icon } from "leaflet"; + +// icons +import busStationIconURL from "../src/assets/icons/bus-station.png"; +import busIconURL from "../src/assets/icons/bus.png"; +import trainStationIconURL from "../src/assets/icons/train-station.png"; +import trainIconURL from "../src/assets/icons/train.png"; +import trainLateIconURL from "../src/assets/icons/train_late.png"; +import trainNotRunningIconURL from "../src/assets/icons/train_notrunning.png"; +import trainOntimeIconURL from "../src/assets/icons/train_ontime.png"; +import tramStationIconURL from "../src/assets/icons/tram-station.png"; + -import trainStationURL from "../src/assets/icons/train-station.png" -import TabTitle from "./components/TabTitle.jsx"; // Fix marker icon issue with Leaflet delete L.Icon.Default.prototype._getIconUrl; L.Icon.Default.mergeOptions({ - iconUrl: - "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png", - iconRetinaUrl: - "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png", - shadowUrl: - "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png", + iconUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png", + iconRetinaUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png", + shadowUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png", }); -let mapCenter = [53.4494762, -7.5029786]; - -if ("geolocation" in navigator) { - navigator.geolocation.getCurrentPosition( - (position) => { - mapCenter = [position.coords.latitude, position.coords.longitude]; - }, - (error) => { - } - ); -} - const icons = new Map(); icons.set( - "train-station", + "IrishRailStation", new Icon({ - iconUrl: trainStationURL, - iconSize: [38,38] + iconUrl: trainStationIconURL, + iconSize: [38, 38], }) -) +); -const markers = [ - { - coords: [53.4494762, -7.5029786], - popup: "Popup lol", - icon: "train-station" - } -] +icons.set( + "IrishRailTrain", + new Icon({ + iconUrl: trainIconURL, + iconSize: [38, 38], + }) +); + +const TRAINSIENT_DATA_API = "https://281bc6mcm5.execute-api.us-east-1.amazonaws.com/transient_data" + +const dataSources = [ + { id: "IrishRailTrains", name: "Irish Rail Trains", url: TRAINSIENT_DATA_API + "?objectType=IrishRailTrain" }, + { id: "source2", name: "Data Source 2", url: "https://api.example.com/source2" }, + { id: "source3", name: "Data Source 3", url: "https://api.example.com/source3" }, +]; function App() { + const [selectedSources, setSelectedSources] = useState([]); + const [markers, setMarkers] = useState([]); + const [loading, setLoading] = useState(false); + + const handleCheckboxChange = (id) => { + setSelectedSources((prev) => + prev.includes(id) ? prev.filter((source) => source !== id) : [...prev, id] + ); + }; + + const fetchData = async () => { + setLoading(true); + const newMarkers = []; + for (const source of dataSources) { + if (selectedSources.includes(source.id)) { + try { + const response = await fetch(source.url); + const data = await response.json(); + data.forEach((item) => { + newMarkers.push({ + coords: [item.latitude, item.longitude], + popup: item.objectType, + icon: item.objectType, + }); + }); + } catch (error) { + console.error(`Error fetching data from ${source.name}:`, error); + } + } + } + setMarkers(newMarkers); + setLoading(false); + }; + return ( <> - -
- - - - - {markers.map(marker => ( - - -

Train 2

-

Train 2

-

Train 2

-

Train 2

-

Train 2

-

Train 2

- -
-
+
+ {loading && ( +
+ Loading data... +
+ )} +
+

Select Data Sources

+ {dataSources.map((source) => ( +
+ handleCheckboxChange(source.id)} + /> + +
))} - + +
+
+ + + {markers.map((marker, index) => ( + + {marker.popup} + + ))} + +
); } -export default App; +export default App; \ No newline at end of file diff --git a/frontend/src/components/TabTitle.jsx b/frontend/src/components/TabTitle.jsx deleted file mode 100644 index 82a3910..0000000 --- a/frontend/src/components/TabTitle.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react"; -import { Helmet } from "react-helmet"; -import favicon from "../../src/assets/icons/train-station.png" - -const TabTitle = () => { - return ( - - Iompar - - - ); -}; - -export default TabTitle; \ No newline at end of file