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