1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
import { type LngLatLike } from "maplibre-gl";
import {
createContext,
useContext,
useEffect,
useState,
type ReactNode,
} from "react";
interface MapState {
paths: Record<string, { center: LngLatLike; zoom: number }>;
userLocation: LngLatLike | null;
hasLocationPermission: boolean;
}
interface MapContextProps {
mapState: MapState;
setUserLocation: (location: LngLatLike | null) => void;
setLocationPermission: (hasPermission: boolean) => void;
updateMapState: (center: LngLatLike, zoom: number, path: string) => void;
}
const MapContext = createContext<MapContextProps | undefined>(undefined);
export const MapProvider = ({ children }: { children: ReactNode }) => {
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.
return {
paths: parsed.paths || {},
userLocation: parsed.userLocation || null,
hasLocationPermission: parsed.hasLocationPermission || false,
};
} catch (e) {
console.error("Error parsing saved map state", e);
}
}
return {
paths: {},
userLocation: null,
hasLocationPermission: false,
};
});
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, path: string) => {
setMapState((prev) => {
const newState = {
...prev,
paths: {
...prev.paths,
[path]: { center, zoom },
},
};
localStorage.setItem("mapState", JSON.stringify(newState));
return newState;
});
};
// 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);
},
{
enableHighAccuracy: true,
maximumAge: Infinity,
timeout: 10000,
}
);
}
}
}, [mapState.hasLocationPermission, mapState.userLocation]);
return (
<MapContext.Provider
value={{
mapState,
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;
};
|