aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/app/hooks/useGeolocation.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/app/hooks/useGeolocation.ts')
-rw-r--r--src/frontend/app/hooks/useGeolocation.ts62
1 files changed, 62 insertions, 0 deletions
diff --git a/src/frontend/app/hooks/useGeolocation.ts b/src/frontend/app/hooks/useGeolocation.ts
new file mode 100644
index 0000000..878420b
--- /dev/null
+++ b/src/frontend/app/hooks/useGeolocation.ts
@@ -0,0 +1,62 @@
+import { useCallback } from "react";
+import { useMap } from "../contexts/MapContext";
+import type { LngLatLike } from "maplibre-gl";
+
+export interface UseGeolocationResult {
+ userLocation: { latitude: number; longitude: number } | null;
+ hasLocationPermission: boolean;
+ requestLocation: () => void;
+}
+
+function lngLatToCoords(
+ loc: LngLatLike
+): { latitude: number; longitude: number } {
+ if (Array.isArray(loc)) {
+ // This codebase stores location as [latitude, longitude] (not the standard
+ // MapLibre [lng, lat] GeoJSON order). See MapContext.tsx where arrays are
+ // set as [position.coords.latitude, position.coords.longitude], and AppMap.tsx
+ // where getLatitude(center) returns center[0].
+ return { latitude: loc[0], longitude: loc[1] };
+ }
+ if ("lat" in loc) {
+ return {
+ latitude: loc.lat,
+ longitude: "lng" in loc ? (loc as any).lng : (loc as any).lon,
+ };
+ }
+ return { latitude: 0, longitude: 0 };
+}
+
+/**
+ * Provides the current user location from the global MapContext.
+ * Location updates are driven by the MapContext's watchPosition subscription
+ * (started automatically when geolocation permission is granted).
+ *
+ * Call `requestLocation()` to prompt the user for permission and start tracking.
+ */
+export function useGeolocation(): UseGeolocationResult {
+ const { mapState, setUserLocation, setLocationPermission } = useMap();
+
+ const requestLocation = useCallback(() => {
+ if (typeof window === "undefined" || !("geolocation" in navigator)) return;
+ navigator.geolocation.getCurrentPosition(
+ (pos) => {
+ setUserLocation([pos.coords.latitude, pos.coords.longitude]);
+ setLocationPermission(true);
+ },
+ () => {
+ setLocationPermission(false);
+ },
+ { enableHighAccuracy: false, maximumAge: 60000, timeout: 10000 }
+ );
+ }, [setUserLocation, setLocationPermission]);
+
+ const rawLoc = mapState.userLocation;
+ const userLocation = rawLoc ? lngLatToCoords(rawLoc) : null;
+
+ return {
+ userLocation,
+ hasLocationPermission: mapState.hasLocationPermission,
+ requestLocation,
+ };
+}