@vidro/map-handler 1.2.12 → 1.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +367 -48
- package/dist/map-handler.js +1 -1
- package/doc/confirmComponent.png +0 -0
- package/examples/full/apidemo.js +46 -43
- package/examples/full/cachedToken.dat +1 -1
- package/examples/full/cachedTokenData.dat +1 -1
- package/examples/full/docker/Docker_compose.yml +14 -0
- package/examples/full/docker/Dockerfile +27 -0
- package/examples/full/index.php +5 -4
- package/examples/full/tester.css +74 -0
- package/examples/full/tester.js +2 -2
- package/examples/react-next/README.md +282 -0
- package/examples/react-next/components/AuthComponent.js +88 -0
- package/examples/react-next/components/MapButtons.js +161 -0
- package/examples/react-next/components/MapFilters.js +120 -0
- package/examples/react-next/components/MapIframe.js +25 -0
- package/examples/react-next/components/MapInfo.js +36 -0
- package/examples/react-next/components/MapLayers.js +60 -0
- package/examples/react-next/components/MapList.js +43 -0
- package/examples/react-next/contexts/auth.js +101 -0
- package/examples/react-next/contexts/maps.js +158 -0
- package/examples/react-next/contexts/messages.js +340 -0
- package/examples/react-next/env.sample +3 -0
- package/examples/react-next/eslint.config.mjs +14 -0
- package/examples/react-next/hooks/useMapEvents.js +118 -0
- package/examples/react-next/jsconfig.json +7 -0
- package/examples/react-next/next.config.mjs +6 -0
- package/examples/react-next/package.json +24 -0
- package/examples/react-next/pages/_app.js +5 -0
- package/examples/react-next/pages/index.js +87 -0
- package/examples/react-next/postcss.config.mjs +8 -0
- package/examples/react-next/public/discord.svg +8 -0
- package/examples/react-next/public/favicon.ico +0 -0
- package/examples/react-next/public/file.svg +1 -0
- package/examples/react-next/public/logo.png +0 -0
- package/examples/react-next/public/next.svg +1 -0
- package/examples/react-next/shared/constants.js +47 -0
- package/examples/react-next/styles/globals.css +24 -0
- package/examples/react-next/tailwind.config.mjs +17 -0
- package/helpers.md +45 -0
- package/package.json +1 -1
- package/src/index.js +263 -23
@@ -0,0 +1,36 @@
|
|
1
|
+
import { useMaps } from "@/contexts/maps";
|
2
|
+
import useMapEvents from "@/hooks/useMapEvents";
|
3
|
+
const MapInfo = () => {
|
4
|
+
useMapEvents();
|
5
|
+
const {
|
6
|
+
zoomLevel,
|
7
|
+
mapScale,
|
8
|
+
clickedCoordinates,
|
9
|
+
map,
|
10
|
+
displayedLayers,
|
11
|
+
mapResolution,
|
12
|
+
} = useMaps();
|
13
|
+
if (!map) return null;
|
14
|
+
return (
|
15
|
+
<div className="absolute bg-white/60 right-0 p-5">
|
16
|
+
<div className="flex flex-col gap-1 text-xs">
|
17
|
+
<div>Zoom level: {zoomLevel}</div>
|
18
|
+
<div>Map scale: {mapScale}</div>
|
19
|
+
<div>Map resolution: {mapResolution}</div>
|
20
|
+
<div>Clicked coordinates: {clickedCoordinates}</div>
|
21
|
+
</div>
|
22
|
+
<div className="bg-black/20 p-5 text-left mt-2">
|
23
|
+
<span>Displayed Layers:</span>
|
24
|
+
|
25
|
+
{displayedLayers && displayedLayers.length > 0 && (
|
26
|
+
<div className="mt-1 flex flex-col gap-1 text-xs">
|
27
|
+
{displayedLayers.map((layer) => (
|
28
|
+
<div key={`lay_${layer}`}> - {layer}</div>
|
29
|
+
))}
|
30
|
+
</div>
|
31
|
+
)}
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
);
|
35
|
+
};
|
36
|
+
export default MapInfo;
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import { useAuth } from "@/contexts/auth";
|
2
|
+
import { useMaps } from "@/contexts/maps";
|
3
|
+
import { useMessages } from "@/contexts/messages";
|
4
|
+
import { useEffect, useState } from "react";
|
5
|
+
|
6
|
+
const MapLayers = () => {
|
7
|
+
const { GetMapInfo, mapId, mapLayers, setActiveLayer } = useMaps();
|
8
|
+
const { ToggleLayer } = useMessages();
|
9
|
+
const { logged } = useAuth();
|
10
|
+
const [selectedLayer, setSelectedLayer] = useState("-1");
|
11
|
+
|
12
|
+
useEffect(() => {
|
13
|
+
if (!mapId) return;
|
14
|
+
GetMapInfo(mapId);
|
15
|
+
}, [mapId]);
|
16
|
+
|
17
|
+
if (!logged) return null;
|
18
|
+
if (!mapId) return null;
|
19
|
+
return (
|
20
|
+
<>
|
21
|
+
<div>
|
22
|
+
{mapLayers && mapLayers.length === 0 && <div>No layers available</div>}
|
23
|
+
|
24
|
+
<div className="m-2 flex gap-2">
|
25
|
+
<label className="block text-sm font-medium text-gray-700 pt-2">
|
26
|
+
Layers
|
27
|
+
</label>
|
28
|
+
{mapLayers && mapLayers.length > 0 && (
|
29
|
+
<select
|
30
|
+
className="border border-gray-300 rounded-md p-2 w-60"
|
31
|
+
onChange={(e) => setSelectedLayer(e.target.value)}
|
32
|
+
value={selectedLayer}
|
33
|
+
>
|
34
|
+
<option value="-1">Select layer...</option>
|
35
|
+
{mapLayers.map((ele) => (
|
36
|
+
<option key={ele.id} value={ele.qgis_name}>
|
37
|
+
{ele.qgis_name} - {ele.alias}
|
38
|
+
</option>
|
39
|
+
))}
|
40
|
+
</select>
|
41
|
+
)}
|
42
|
+
|
43
|
+
<button
|
44
|
+
onClick={(e) => {
|
45
|
+
console.log("Toggle layer", selectedLayer);
|
46
|
+
setActiveLayer(selectedLayer);
|
47
|
+
ToggleLayer(selectedLayer);
|
48
|
+
}}
|
49
|
+
disabled={selectedLayer === "-1"}
|
50
|
+
className="border border-gray-300 bg-black text-white rounded-md p-2 mt-1 text-xs"
|
51
|
+
>
|
52
|
+
Toggle layer
|
53
|
+
</button>
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
</>
|
57
|
+
);
|
58
|
+
};
|
59
|
+
|
60
|
+
export default MapLayers;
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import { useAuth } from "@/contexts/auth";
|
2
|
+
import { useMaps } from "@/contexts/maps";
|
3
|
+
import { useState } from "react";
|
4
|
+
|
5
|
+
const MapList = () => {
|
6
|
+
const { GetMap } = useMaps();
|
7
|
+
const { projects, logged } = useAuth();
|
8
|
+
const [selectedMap, setSelectedMap] = useState("-1");
|
9
|
+
if (!logged) return null;
|
10
|
+
return (
|
11
|
+
<div>
|
12
|
+
<div className="m-2 flex gap-2">
|
13
|
+
<label className="block text-sm font-medium text-gray-700 pt-2">
|
14
|
+
Maps
|
15
|
+
</label>
|
16
|
+
<select
|
17
|
+
className="border border-gray-300 rounded-md p-2 w-32"
|
18
|
+
onChange={(e) => setSelectedMap(e.target.value)}
|
19
|
+
value={selectedMap}
|
20
|
+
>
|
21
|
+
<option value="-1">Select a map</option>
|
22
|
+
{projects.map((projectId) => (
|
23
|
+
<option key={projectId} value={projectId}>
|
24
|
+
{projectId}
|
25
|
+
</option>
|
26
|
+
))}
|
27
|
+
</select>
|
28
|
+
|
29
|
+
<button
|
30
|
+
onClick={(e) => {
|
31
|
+
GetMap(selectedMap);
|
32
|
+
}}
|
33
|
+
disabled={selectedMap === "-1"}
|
34
|
+
className="border border-gray-300 bg-black text-white rounded-md p-2 mt-1 text-xs"
|
35
|
+
>
|
36
|
+
Load map
|
37
|
+
</button>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
);
|
41
|
+
};
|
42
|
+
|
43
|
+
export default MapList;
|
@@ -0,0 +1,101 @@
|
|
1
|
+
"use client";
|
2
|
+
import { createContext, useContext, useState } from "react";
|
3
|
+
import { useRouter } from "next/navigation";
|
4
|
+
|
5
|
+
const AuthContext = createContext({});
|
6
|
+
|
7
|
+
export const AuthProvider = ({ children }) => {
|
8
|
+
const [apiUrl, setApiUrl] = useState(
|
9
|
+
process.env.NEXT_PUBLIC_APIURL ? process.env.NEXT_PUBLIC_APIURL : ""
|
10
|
+
);
|
11
|
+
const [logged, setLogged] = useState(null);
|
12
|
+
const [token, setToken] = useState(null);
|
13
|
+
const [userId, setUserId] = useState(null);
|
14
|
+
const [projects, setProjects] = useState([]);
|
15
|
+
const router = useRouter();
|
16
|
+
|
17
|
+
const resetAuthState = () => {
|
18
|
+
setLogged(false);
|
19
|
+
setToken(null);
|
20
|
+
setUserId(null);
|
21
|
+
setProjects([]);
|
22
|
+
};
|
23
|
+
|
24
|
+
const login = async (email, password) => {
|
25
|
+
try {
|
26
|
+
const response = await fetch(`${apiUrl}letsgo`, {
|
27
|
+
method: "POST",
|
28
|
+
headers: {
|
29
|
+
"Content-Type": "application/json",
|
30
|
+
},
|
31
|
+
body: JSON.stringify({ user: email, pwd: password }),
|
32
|
+
});
|
33
|
+
|
34
|
+
const data = await response.json();
|
35
|
+
console.log("login", data);
|
36
|
+
|
37
|
+
if (!response.ok) {
|
38
|
+
return { error: true, message: data.message || "Login failed" };
|
39
|
+
}
|
40
|
+
|
41
|
+
setToken(data.message.token);
|
42
|
+
setUserId(data.message.id);
|
43
|
+
|
44
|
+
setLogged(true);
|
45
|
+
setProjects(data.message.maps);
|
46
|
+
} catch (error) {
|
47
|
+
console.error("Login error:", error);
|
48
|
+
return { error: true, message: "An unexpected error occurred" };
|
49
|
+
}
|
50
|
+
|
51
|
+
return { error: false };
|
52
|
+
};
|
53
|
+
|
54
|
+
const logout = async () => {
|
55
|
+
console.log("logout", token);
|
56
|
+
try {
|
57
|
+
const response = await fetch(`${apiUrl}logout`, {
|
58
|
+
method: "DELETE",
|
59
|
+
headers: {
|
60
|
+
"Content-Type": "application/json",
|
61
|
+
Authorization: `Bearer ${token}`,
|
62
|
+
},
|
63
|
+
});
|
64
|
+
|
65
|
+
const data = await response.json();
|
66
|
+
console.log("logout", data);
|
67
|
+
|
68
|
+
if (!response.ok) {
|
69
|
+
return { error: true, message: data.message || "Logout failed" };
|
70
|
+
}
|
71
|
+
|
72
|
+
// Reset auth state and remove token cookie
|
73
|
+
resetAuthState();
|
74
|
+
router.push("/");
|
75
|
+
|
76
|
+
return { error: false };
|
77
|
+
} catch (error) {
|
78
|
+
console.error("Logout error:", error);
|
79
|
+
return { error: true, message: "An unexpected error occurred" };
|
80
|
+
}
|
81
|
+
};
|
82
|
+
|
83
|
+
return (
|
84
|
+
<AuthContext.Provider
|
85
|
+
value={{
|
86
|
+
logged,
|
87
|
+
token,
|
88
|
+
login,
|
89
|
+
logout,
|
90
|
+
userId,
|
91
|
+
projects,
|
92
|
+
apiUrl,
|
93
|
+
setApiUrl,
|
94
|
+
}}
|
95
|
+
>
|
96
|
+
{children}
|
97
|
+
</AuthContext.Provider>
|
98
|
+
);
|
99
|
+
};
|
100
|
+
|
101
|
+
export const useAuth = () => useContext(AuthContext);
|
@@ -0,0 +1,158 @@
|
|
1
|
+
"use client";
|
2
|
+
import { createContext, useContext, useState, useEffect } from "react";
|
3
|
+
import { useAuth } from "./auth";
|
4
|
+
|
5
|
+
const MapsContext = createContext({});
|
6
|
+
|
7
|
+
export const MapsProvider = ({ children }) => {
|
8
|
+
const { apiUrl, token } = useAuth();
|
9
|
+
const [map, setMap] = useState(null);
|
10
|
+
const [mapId, setMapId] = useState(null);
|
11
|
+
|
12
|
+
const [mapError, setMapError] = useState(null);
|
13
|
+
const [mapReady, setMapReady] = useState(false);
|
14
|
+
|
15
|
+
const [sessionToken, setSessionToken] = useState(null);
|
16
|
+
const [currentMapAction, setCurrentMapAction] = useState(null);
|
17
|
+
const [clickedCoordinates, setClickedCoordinates] = useState(null);
|
18
|
+
const [bboxCoordinates, setBboxcoordinates] = useState(null);
|
19
|
+
const [zoomLevel, setZoomLevel] = useState(null);
|
20
|
+
const [mapScale, setMapScale] = useState(null);
|
21
|
+
const [mapResolution, setMapResolution] = useState(null);
|
22
|
+
const [srid, setSrid] = useState(null);
|
23
|
+
|
24
|
+
//geolocations
|
25
|
+
const [geolocalizing, setGeolocalizing] = useState(false);
|
26
|
+
const [geolocalizingstatus, setGeolocalizingStatus] = useState(null);
|
27
|
+
const [userGeoPosition, setUserGeoPosition] = useState(null);
|
28
|
+
|
29
|
+
//measure
|
30
|
+
const [measureStatus, setMeasureStatus] = useState(null);
|
31
|
+
|
32
|
+
//layers
|
33
|
+
const [displayedLayers, setDisplayedLayers] = useState([]);
|
34
|
+
const [activeLayer, setActiveLayer] = useState(null);
|
35
|
+
const [mapLayers, setMapLayers] = useState(null);
|
36
|
+
|
37
|
+
const [infoLayerSource, setInfoLayerSource] = useState([]); //layer from info is received
|
38
|
+
|
39
|
+
//filters
|
40
|
+
const [configuredFilters, setConfiguredFilters] = useState(null); //backoffice configured filters
|
41
|
+
const [mapFilters, setMapfilters] = useState(null);
|
42
|
+
const [filtersApplied, setFiltersApplied] = useState(false);
|
43
|
+
const [activeFilters, setActiveFilters] = useState([]);
|
44
|
+
|
45
|
+
//tools
|
46
|
+
const [selectedTool, setSelectedTool] = useState(null);
|
47
|
+
|
48
|
+
const GetMap = async (id) => {
|
49
|
+
let url = `${apiUrl}map/${id}`;
|
50
|
+
|
51
|
+
try {
|
52
|
+
const response = await fetch(url, {
|
53
|
+
method: "GET",
|
54
|
+
headers: {
|
55
|
+
"Content-Type": "application/json",
|
56
|
+
Authorization: `Bearer ${token}`,
|
57
|
+
},
|
58
|
+
});
|
59
|
+
const data = await response.json();
|
60
|
+
console.log("GetMap", data);
|
61
|
+
setMapId(id);
|
62
|
+
setMapError(false);
|
63
|
+
setSessionToken(data.message.sessionToken);
|
64
|
+
setMap(
|
65
|
+
`${data.message.iframe}?sessionToken=${data.message.sessionToken}`
|
66
|
+
);
|
67
|
+
return;
|
68
|
+
} catch (error) {
|
69
|
+
console.error("Error fetching map:", error);
|
70
|
+
setSessionToken(null);
|
71
|
+
setMap(null);
|
72
|
+
setMapId(null);
|
73
|
+
throw error;
|
74
|
+
}
|
75
|
+
};
|
76
|
+
|
77
|
+
const GetMapInfo = async (id) => {
|
78
|
+
let url = `${apiUrl}map/detail/${id}`;
|
79
|
+
|
80
|
+
try {
|
81
|
+
const response = await fetch(url, {
|
82
|
+
method: "GET",
|
83
|
+
headers: {
|
84
|
+
"Content-Type": "application/json",
|
85
|
+
Authorization: `Bearer ${token}`,
|
86
|
+
},
|
87
|
+
});
|
88
|
+
const data = await response.json();
|
89
|
+
console.log("GetMapInfo", data);
|
90
|
+
console.log("Layers", data.message.layers);
|
91
|
+
setMapLayers(data.message.layers);
|
92
|
+
setConfiguredFilters(data.message.layerFilters);
|
93
|
+
return;
|
94
|
+
} catch (error) {
|
95
|
+
console.error("Error fetching map info:", error);
|
96
|
+
|
97
|
+
setMapLayers(null);
|
98
|
+
throw error;
|
99
|
+
}
|
100
|
+
};
|
101
|
+
return (
|
102
|
+
<MapsContext.Provider
|
103
|
+
value={{
|
104
|
+
mapId,
|
105
|
+
setMapId,
|
106
|
+
GetMap,
|
107
|
+
map,
|
108
|
+
sessionToken,
|
109
|
+
mapError,
|
110
|
+
mapReady,
|
111
|
+
setMapReady,
|
112
|
+
displayedLayers,
|
113
|
+
setDisplayedLayers,
|
114
|
+
activeLayer,
|
115
|
+
setActiveLayer,
|
116
|
+
currentMapAction,
|
117
|
+
setCurrentMapAction,
|
118
|
+
mapFilters,
|
119
|
+
setMapfilters,
|
120
|
+
activeFilters,
|
121
|
+
setActiveFilters,
|
122
|
+
configuredFilters,
|
123
|
+
infoLayerSource,
|
124
|
+
setInfoLayerSource,
|
125
|
+
clickedCoordinates,
|
126
|
+
setClickedCoordinates,
|
127
|
+
bboxCoordinates,
|
128
|
+
setBboxcoordinates,
|
129
|
+
srid,
|
130
|
+
setSrid,
|
131
|
+
geolocalizing,
|
132
|
+
setGeolocalizing,
|
133
|
+
geolocalizingstatus,
|
134
|
+
setGeolocalizingStatus,
|
135
|
+
userGeoPosition,
|
136
|
+
measureStatus,
|
137
|
+
setMeasureStatus,
|
138
|
+
selectedTool,
|
139
|
+
setSelectedTool,
|
140
|
+
filtersApplied,
|
141
|
+
setFiltersApplied,
|
142
|
+
zoomLevel,
|
143
|
+
setZoomLevel,
|
144
|
+
mapScale,
|
145
|
+
setMapScale,
|
146
|
+
setSessionToken,
|
147
|
+
mapLayers,
|
148
|
+
GetMapInfo,
|
149
|
+
mapResolution,
|
150
|
+
setMapResolution,
|
151
|
+
}}
|
152
|
+
>
|
153
|
+
{children}
|
154
|
+
</MapsContext.Provider>
|
155
|
+
);
|
156
|
+
};
|
157
|
+
|
158
|
+
export const useMaps = () => useContext(MapsContext);
|