@vidro/map-handler 1.2.10 → 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.
Files changed (43) hide show
  1. package/README.md +442 -32
  2. package/dist/map-handler.js +1 -1
  3. package/doc/animation.png +0 -0
  4. package/doc/confirmComponent.png +0 -0
  5. package/examples/full/apidemo.js +46 -43
  6. package/examples/full/cachedToken.dat +1 -1
  7. package/examples/full/cachedTokenData.dat +1 -1
  8. package/examples/full/docker/Docker_compose.yml +14 -0
  9. package/examples/full/docker/Dockerfile +27 -0
  10. package/examples/full/index.php +5 -4
  11. package/examples/full/tester.css +74 -0
  12. package/examples/full/tester.js +2 -2
  13. package/examples/react-next/README.md +282 -0
  14. package/examples/react-next/components/AuthComponent.js +88 -0
  15. package/examples/react-next/components/MapButtons.js +161 -0
  16. package/examples/react-next/components/MapFilters.js +120 -0
  17. package/examples/react-next/components/MapIframe.js +25 -0
  18. package/examples/react-next/components/MapInfo.js +36 -0
  19. package/examples/react-next/components/MapLayers.js +60 -0
  20. package/examples/react-next/components/MapList.js +43 -0
  21. package/examples/react-next/contexts/auth.js +101 -0
  22. package/examples/react-next/contexts/maps.js +158 -0
  23. package/examples/react-next/contexts/messages.js +340 -0
  24. package/examples/react-next/env.sample +3 -0
  25. package/examples/react-next/eslint.config.mjs +14 -0
  26. package/examples/react-next/hooks/useMapEvents.js +118 -0
  27. package/examples/react-next/jsconfig.json +7 -0
  28. package/examples/react-next/next.config.mjs +6 -0
  29. package/examples/react-next/package.json +24 -0
  30. package/examples/react-next/pages/_app.js +5 -0
  31. package/examples/react-next/pages/index.js +87 -0
  32. package/examples/react-next/postcss.config.mjs +8 -0
  33. package/examples/react-next/public/discord.svg +8 -0
  34. package/examples/react-next/public/favicon.ico +0 -0
  35. package/examples/react-next/public/file.svg +1 -0
  36. package/examples/react-next/public/logo.png +0 -0
  37. package/examples/react-next/public/next.svg +1 -0
  38. package/examples/react-next/shared/constants.js +47 -0
  39. package/examples/react-next/styles/globals.css +24 -0
  40. package/examples/react-next/tailwind.config.mjs +17 -0
  41. package/helpers.md +45 -0
  42. package/package.json +1 -1
  43. package/src/index.js +305 -20
@@ -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);