From f65b4e1e0d5648038823962349279be4badc68ed Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Tue, 24 Jun 2025 16:02:02 +0200 Subject: Refactor navigation structure: move NavBar to its own component, implement geolocation handling, and remove unused isWithinVigo function from AppContext. --- package-lock.json | 92 ++++++++-------------------------- src/frontend/app/AppContext.tsx | 40 --------------- src/frontend/app/components/NavBar.tsx | 84 +++++++++++++++++++++++++++++++ src/frontend/app/root.tsx | 54 +++++++------------- 4 files changed, 124 insertions(+), 146 deletions(-) create mode 100644 src/frontend/app/components/NavBar.tsx diff --git a/package-lock.json b/package-lock.json index 18a459f..07400f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,7 @@ ], "devDependencies": { "concurrently": "^9.1.2", - "prettier": "^3.5.3", - "vite-tsconfig-paths": "^5.1.4" + "prettier": "^3.5.3" } }, "node_modules/@ampproject/remapping": { @@ -523,7 +522,6 @@ "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } @@ -541,7 +539,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -559,7 +556,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -577,7 +573,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -595,7 +590,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -613,7 +607,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -631,7 +624,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -649,7 +641,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -667,7 +658,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -685,7 +675,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -703,7 +692,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -721,7 +709,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -739,7 +726,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -757,7 +743,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -775,7 +760,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -793,7 +777,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -811,7 +794,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -829,7 +811,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -847,7 +828,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -865,7 +845,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -883,7 +862,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -901,7 +879,6 @@ "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } @@ -919,7 +896,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -937,7 +913,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -955,7 +930,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -1752,8 +1726,7 @@ "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.41.1", @@ -1767,8 +1740,7 @@ "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.41.1", @@ -1782,8 +1754,7 @@ "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.41.1", @@ -1797,8 +1768,7 @@ "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.41.1", @@ -1812,8 +1782,7 @@ "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.41.1", @@ -1827,8 +1796,7 @@ "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.41.1", @@ -1842,8 +1810,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.41.1", @@ -1857,8 +1824,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.41.1", @@ -1872,8 +1838,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.41.1", @@ -1887,8 +1852,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { "version": "4.41.1", @@ -1902,8 +1866,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "version": "4.41.1", @@ -1917,8 +1880,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.41.1", @@ -1932,8 +1894,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.41.1", @@ -1947,8 +1908,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.41.1", @@ -1962,8 +1922,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.41.1", @@ -1990,8 +1949,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.41.1", @@ -2005,8 +1963,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.41.1", @@ -2020,8 +1977,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.41.1", @@ -2035,8 +1991,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@types/estree": { "version": "1.0.7", @@ -3798,7 +3753,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -6830,10 +6784,8 @@ "react-map-gl": "^8.0.4", "typescript": "^5.8.3", "typescript-eslint": "^8.32.0", - "vite": "^6.3.5" - }, - "engines": { - "node": ">=20.0.0" + "vite": "^6.3.5", + "vite-tsconfig-paths": "5.1.4" }, "optionalDependencies": { "@rollup/rollup-linux-x64-gnu": "*" diff --git a/src/frontend/app/AppContext.tsx b/src/frontend/app/AppContext.tsx index 7ca85bd..d8db66d 100644 --- a/src/frontend/app/AppContext.tsx +++ b/src/frontend/app/AppContext.tsx @@ -113,46 +113,6 @@ export const AppProvider = ({ children }: { children: ReactNode }) => { }; }); - // Helper: check if coordinates are within Vigo bounds - function isWithinVigo(lngLat: LngLatLike): boolean { - let lng: number, lat: number; - if (Array.isArray(lngLat)) { - [lng, lat] = lngLat; - } else if ('lng' in lngLat && 'lat' in lngLat) { - lng = lngLat.lng; - lat = lngLat.lat; - } else { - return false; - } - // Rough bounding box for Vigo - return lat >= 42.18 && lat <= 42.30 && lng >= -8.78 && lng <= -8.65; - } - - // On app load, if mapPositionMode is 'gps', try to get GPS and set map center - useEffect(() => { - if (mapPositionMode === 'gps') { - if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition( - (position) => { - const { latitude, longitude } = position.coords; - const coords: LngLatLike = [latitude, longitude]; - if (isWithinVigo(coords)) { - setMapState(prev => { - const newState = { ...prev, center: coords, zoom: 16, userLocation: coords }; - localStorage.setItem('mapState', JSON.stringify(newState)); - return newState; - }); - } - }, - () => { - // Ignore error, fallback to last - } - ); - } - } - // If 'last', do nothing (already loaded from localStorage) - }, [mapPositionMode]); - const setMapCenter = (center: LngLatLike) => { setMapState(prev => { const newState = { ...prev, center }; diff --git a/src/frontend/app/components/NavBar.tsx b/src/frontend/app/components/NavBar.tsx new file mode 100644 index 0000000..091cc21 --- /dev/null +++ b/src/frontend/app/components/NavBar.tsx @@ -0,0 +1,84 @@ +import { Link } from "react-router"; +import { Map, MapPin, Settings } from "lucide-react"; +import { useApp } from "../AppContext"; +import type { LngLatLike } from "maplibre-gl"; + +// Helper: check if coordinates are within Vigo bounds +function isWithinVigo(lngLat: LngLatLike): boolean { + let lng: number, lat: number; + if (Array.isArray(lngLat)) { + [lng, lat] = lngLat; + } else if ('lng' in lngLat && 'lat' in lngLat) { + lng = lngLat.lng; + lat = lngLat.lat; + } else { + return false; + } + // Rough bounding box for Vigo + return lat >= 42.18 && lat <= 42.30 && lng >= -8.78 && lng <= -8.65; +} + +export default function NavBar() { + const { mapState, updateMapState, mapPositionMode } = useApp(); + + const navItems = [ + { + name: 'Paradas', + icon: MapPin, + path: '/stops' + }, + { + name: 'Mapa', + icon: Map, + path: '/map', + callback: () => { + if (mapPositionMode !== 'gps') { + return; + } + + if (!('geolocation' in navigator)) { + return; + } + + navigator.geolocation.getCurrentPosition( + (position) => { + const { latitude, longitude } = position.coords; + const coords: LngLatLike = [latitude, longitude]; + if (isWithinVigo(coords)) { + updateMapState(coords, 16); + } + }, + () => { } + ); + } + }, + { + name: 'Ajustes', + icon: Settings, + path: '/settings' + } + ]; + + return ( + + ); +} diff --git a/src/frontend/app/root.tsx b/src/frontend/app/root.tsx index d90dba0..9d59ce7 100644 --- a/src/frontend/app/root.tsx +++ b/src/frontend/app/root.tsx @@ -16,9 +16,8 @@ import "./root.css"; import "maplibre-theme/icons.default.css"; import "maplibre-theme/modern.css"; import { Protocol } from "pmtiles"; -import maplibregl from "maplibre-gl"; +import maplibregl, { type LngLatLike } from "maplibre-gl"; import { AppProvider } from "./AppContext"; -import { Map, MapPin, Settings } from "lucide-react"; const pmtiles = new Protocol(); maplibregl.addProtocol("pmtiles", pmtiles.tile); //#endregion @@ -81,48 +80,31 @@ export function Layout({ children }: { children: React.ReactNode }) { ); } -export default function App() { - const navItems = [ - { - name: 'Paradas', - icon: MapPin, - path: '/stops' - }, - { - name: 'Mapa', - icon: Map, - path: '/map' - }, - { - name: 'Ajustes', - icon: Settings, - path: '/settings' + // Helper: check if coordinates are within Vigo bounds + function isWithinVigo(lngLat: LngLatLike): boolean { + let lng: number, lat: number; + if (Array.isArray(lngLat)) { + [lng, lat] = lngLat; + } else if ('lng' in lngLat && 'lat' in lngLat) { + lng = lngLat.lng; + lat = lngLat.lat; + } else { + return false; } - ]; + // Rough bounding box for Vigo + return lat >= 42.18 && lat <= 42.30 && lng >= -8.78 && lng <= -8.65; + } +import NavBar from "./components/NavBar"; + +export default function App() { return (
-- cgit v1.3