aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/app/contexts/MapContext.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/app/contexts/MapContext.tsx')
-rw-r--r--src/frontend/app/contexts/MapContext.tsx151
1 files changed, 151 insertions, 0 deletions
diff --git a/src/frontend/app/contexts/MapContext.tsx b/src/frontend/app/contexts/MapContext.tsx
new file mode 100644
index 0000000..b47b67f
--- /dev/null
+++ b/src/frontend/app/contexts/MapContext.tsx
@@ -0,0 +1,151 @@
+import { type LngLatLike } from "maplibre-gl";
+import {
+ createContext,
+ useContext,
+ useEffect,
+ useState,
+ type ReactNode,
+} from "react";
+import { getRegionConfig } from "../config/RegionConfig";
+import { useSettings } from "./SettingsContext";
+
+interface MapState {
+ center: LngLatLike;
+ zoom: number;
+ userLocation: LngLatLike | null;
+ hasLocationPermission: boolean;
+}
+
+interface MapContextProps {
+ mapState: MapState;
+ setMapCenter: (center: LngLatLike) => void;
+ setMapZoom: (zoom: number) => void;
+ setUserLocation: (location: LngLatLike | null) => void;
+ setLocationPermission: (hasPermission: boolean) => void;
+ updateMapState: (center: LngLatLike, zoom: number) => void;
+}
+
+const MapContext = createContext<MapContextProps | undefined>(undefined);
+
+export const MapProvider = ({ children }: { children: ReactNode }) => {
+ const { region } = useSettings();
+ const [prevRegion, setPrevRegion] = useState(region);
+
+ const [mapState, setMapState] = useState<MapState>(() => {
+ const savedMapState = localStorage.getItem("mapState");
+ if (savedMapState) {
+ try {
+ const parsed = JSON.parse(savedMapState);
+ // Validate that the saved center is valid if needed, or just trust it.
+ // We might want to ensure we have a fallback if the region changed while the app was closed?
+ // But for now, let's stick to the existing logic.
+ const regionConfig = getRegionConfig(region);
+ return {
+ center: parsed.center || regionConfig.defaultCenter,
+ zoom: parsed.zoom || regionConfig.defaultZoom,
+ userLocation: parsed.userLocation || null,
+ hasLocationPermission: parsed.hasLocationPermission || false,
+ };
+ } catch (e) {
+ console.error("Error parsing saved map state", e);
+ }
+ }
+ const regionConfig = getRegionConfig(region);
+ return {
+ center: regionConfig.defaultCenter,
+ zoom: regionConfig.defaultZoom,
+ userLocation: null,
+ hasLocationPermission: false,
+ };
+ });
+
+ const setMapCenter = (center: LngLatLike) => {
+ setMapState((prev) => {
+ const newState = { ...prev, center };
+ localStorage.setItem("mapState", JSON.stringify(newState));
+ return newState;
+ });
+ };
+
+ const setMapZoom = (zoom: number) => {
+ setMapState((prev) => {
+ const newState = { ...prev, zoom };
+ localStorage.setItem("mapState", JSON.stringify(newState));
+ return newState;
+ });
+ };
+
+ const setUserLocation = (userLocation: LngLatLike | null) => {
+ setMapState((prev) => {
+ const newState = { ...prev, userLocation };
+ localStorage.setItem("mapState", JSON.stringify(newState));
+ return newState;
+ });
+ };
+
+ const setLocationPermission = (hasLocationPermission: boolean) => {
+ setMapState((prev) => {
+ const newState = { ...prev, hasLocationPermission };
+ localStorage.setItem("mapState", JSON.stringify(newState));
+ return newState;
+ });
+ };
+
+ const updateMapState = (center: LngLatLike, zoom: number) => {
+ setMapState((prev) => {
+ const newState = { ...prev, center, zoom };
+ localStorage.setItem("mapState", JSON.stringify(newState));
+ return newState;
+ });
+ };
+
+ // Sync map state when region changes
+ useEffect(() => {
+ if (region !== prevRegion) {
+ const regionConfig = getRegionConfig(region);
+ updateMapState(regionConfig.defaultCenter, regionConfig.defaultZoom);
+ setPrevRegion(region);
+ }
+ }, [region, prevRegion]);
+
+ // Try to get user location on load if permission was granted
+ useEffect(() => {
+ if (mapState.hasLocationPermission && !mapState.userLocation) {
+ if (navigator.geolocation) {
+ navigator.geolocation.getCurrentPosition(
+ (position) => {
+ const { latitude, longitude } = position.coords;
+ setUserLocation([latitude, longitude]);
+ },
+ (error) => {
+ console.error("Error getting location:", error);
+ setLocationPermission(false);
+ }
+ );
+ }
+ }
+ }, [mapState.hasLocationPermission, mapState.userLocation]);
+
+ return (
+ <MapContext.Provider
+ value={{
+ mapState,
+ setMapCenter,
+ setMapZoom,
+ setUserLocation,
+ setLocationPermission,
+ updateMapState,
+ }}
+ >
+ {children}
+ </MapContext.Provider>
+ );
+};
+
+export const useMap = () => {
+ const context = useContext(MapContext);
+ if (!context) {
+ throw new Error("useMap must be used within a MapProvider");
+ }
+ return context;
+};