@eeacms/volto-arcgis-block 0.1.378 → 0.1.380
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/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
### [0.1.380](https://github.com/eea/volto-arcgis-block/compare/0.1.379...0.1.380) - 20 August 2025
|
|
8
|
+
|
|
9
|
+
### [0.1.379](https://github.com/eea/volto-arcgis-block/compare/0.1.378...0.1.379) - 11 August 2025
|
|
10
|
+
|
|
11
|
+
#### :hammer_and_wrench: Others
|
|
12
|
+
|
|
13
|
+
- Merge pull request #999 from eea/develop [Unai Bolivar - [`f5b976f`](https://github.com/eea/volto-arcgis-block/commit/f5b976fdc7e5568973e7db87c29c05f8fe2abcbd)]
|
|
14
|
+
- Merge pull request #998 from eea/CLMS-LOCAL-STORAGE-ISSUES-REFACTOR-CLEAN [Unai Bolivar - [`3b84fbd`](https://github.com/eea/volto-arcgis-block/commit/3b84fbd1cc3706976cc746a95c6885da7a746e22)]
|
|
15
|
+
- (lint): cleared console statements [Unai Bolivar - [`f6d649d`](https://github.com/eea/volto-arcgis-block/commit/f6d649d51d9254a250e49ca31b83bc4cc8c6b30a)]
|
|
16
|
+
- (bug): implemented safe store and recall for all user data in mapviewer fix [Unai Bolivar - [`a0491a7`](https://github.com/eea/volto-arcgis-block/commit/a0491a7bbeffdcd527eabc91b716757d680ea5d3)]
|
|
17
|
+
- (bug): rendering session data correctly [Unai Bolivar - [`0fd8434`](https://github.com/eea/volto-arcgis-block/commit/0fd843442b72b7d0980f98e182f4ec68dc00850c)]
|
|
18
|
+
- (bug): wrapping mapviewer in mapviewerstatemonitor to control and eliminate multiple mapviewer mounts and race conditions [Unai Bolivar - [`c3e5232`](https://github.com/eea/volto-arcgis-block/commit/c3e5232b64f318256f504575f7e6ee685d80e121)]
|
|
19
|
+
- (bug): fixed user anonymous session storage maintenance [Unai Bolivar - [`7bb1054`](https://github.com/eea/volto-arcgis-block/commit/7bb105406e272d73c115b1515313723890830d8e)]
|
|
20
|
+
- (bug): saving updates to retrieve current jsx file [Unai Bolivar - [`10e8b69`](https://github.com/eea/volto-arcgis-block/commit/10e8b69a2f9c6ebda49864bb431c6f8e4a49fa66)]
|
|
21
|
+
- (bug): prettified the file [Unai Bolivar - [`e561931`](https://github.com/eea/volto-arcgis-block/commit/e5619310b30c1c8935735d8de53939cc551fb1ba)]
|
|
22
|
+
- (bug): moved status monitoring to mapviewer HOC component for better synchronization and widget updates that actually catch the user login and userID information and setup session storage accordingly before proceeding with a full state update after mount is ready. [Unai Bolivar - [`16dd623`](https://github.com/eea/volto-arcgis-block/commit/16dd62302b4fa520185b4d9957e69e41c31e1fa6)]
|
|
7
23
|
### [0.1.378](https://github.com/eea/volto-arcgis-block/compare/0.1.377...0.1.378) - 11 August 2025
|
|
8
24
|
|
|
9
25
|
### [0.1.377](https://github.com/eea/volto-arcgis-block/compare/0.1.376...0.1.377) - 30 July 2025
|
package/package.json
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
createRef,
|
|
3
|
+
createContext,
|
|
4
|
+
useContext,
|
|
5
|
+
useState,
|
|
6
|
+
useEffect,
|
|
7
|
+
useCallback,
|
|
8
|
+
useRef,
|
|
9
|
+
} from 'react';
|
|
2
10
|
import './css/ArcgisMap.css';
|
|
3
11
|
import classNames from 'classnames';
|
|
4
12
|
import { loadModules, loadCss } from 'esri-loader';
|
|
@@ -28,13 +36,417 @@ import { getTaxonomy } from '@eeacms/volto-taxonomy/actions';
|
|
|
28
36
|
//import "isomorphic-fetch"; <-- Necessary to use fetch?
|
|
29
37
|
var Map, MapView, Zoom, intl, Basemap, WebTileLayer, Extent;
|
|
30
38
|
let mapStatus = {};
|
|
39
|
+
|
|
31
40
|
const CheckLanguage = () => {
|
|
32
41
|
const { locale } = useIntl();
|
|
33
42
|
intl.setLocale(locale);
|
|
34
43
|
return null;
|
|
35
44
|
};
|
|
36
45
|
|
|
46
|
+
// Enhanced UserContext and Provider with state monitoring capabilities
|
|
47
|
+
const UserContext = createContext({ user_id: null, isLoggedIn: false });
|
|
48
|
+
const useUserContext = () => useContext(UserContext);
|
|
49
|
+
|
|
50
|
+
// Enhanced UserProvider with state change monitoring
|
|
51
|
+
const UserProvider = ({ children }) => {
|
|
52
|
+
const cartState = useCartState();
|
|
53
|
+
|
|
54
|
+
// Direct transformation of cart state to user context format
|
|
55
|
+
// No local state needed - context reactively updates when cartState changes
|
|
56
|
+
const userContextValue = {
|
|
57
|
+
user_id: cartState?.user_id || null,
|
|
58
|
+
isLoggedIn: cartState?.isLoggedIn || false,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Show loading only when cart state is completely undefined (initial load)
|
|
62
|
+
// Prevents UI flicker by distinguishing between "loading" and "logged out" states
|
|
63
|
+
if (cartState === undefined) {
|
|
64
|
+
return (
|
|
65
|
+
<div className="loading-container">
|
|
66
|
+
<div className="loading-text">Loading...</div>
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<UserContext.Provider value={userContextValue}>
|
|
73
|
+
{children}
|
|
74
|
+
</UserContext.Provider>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// MapViewer State Monitor - Functional wrapper that monitors useCartState changes
|
|
79
|
+
// and ensures the class component always receives the latest authentication state
|
|
80
|
+
const MapViewerStateMonitor = ({ children, onUserStateChange }) => {
|
|
81
|
+
const cartState = useCartState();
|
|
82
|
+
const prevCartStateRef = useRef(null);
|
|
83
|
+
|
|
84
|
+
// Monitor cart state changes and notify parent component
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (cartState !== undefined) {
|
|
87
|
+
const currentUserState = {
|
|
88
|
+
user_id: cartState?.user_id || null,
|
|
89
|
+
isLoggedIn: cartState?.isLoggedIn || false,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Compare with previous state to detect changes
|
|
93
|
+
if (prevCartStateRef.current !== null) {
|
|
94
|
+
const hasUserIdChanged =
|
|
95
|
+
prevCartStateRef.current.user_id !== currentUserState.user_id;
|
|
96
|
+
const hasLoggedInChanged =
|
|
97
|
+
prevCartStateRef.current.isLoggedIn !== currentUserState.isLoggedIn;
|
|
98
|
+
|
|
99
|
+
if (hasUserIdChanged || hasLoggedInChanged) {
|
|
100
|
+
/* eslint-disable no-console */
|
|
101
|
+
console.log('[MapViewerStateMonitor] User state change detected:', {
|
|
102
|
+
previous: prevCartStateRef.current,
|
|
103
|
+
current: currentUserState,
|
|
104
|
+
userIdChanged: hasUserIdChanged,
|
|
105
|
+
loggedInChanged: hasLoggedInChanged,
|
|
106
|
+
});
|
|
107
|
+
/* eslint-enable no-console */
|
|
108
|
+
|
|
109
|
+
// Notify parent component of state change
|
|
110
|
+
if (onUserStateChange) {
|
|
111
|
+
onUserStateChange(currentUserState, prevCartStateRef.current);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Update previous state using ref (doesn't cause re-renders)
|
|
117
|
+
prevCartStateRef.current = currentUserState;
|
|
118
|
+
}
|
|
119
|
+
}, [cartState, onUserStateChange]);
|
|
120
|
+
|
|
121
|
+
return children;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// UserStorageManager now consumes user state directly from UserContext
|
|
125
|
+
// Eliminates prop drilling and ensures consistent user state access
|
|
126
|
+
const UserStorageManager = ({ children, onStorageManaged }) => {
|
|
127
|
+
const { user_id: userID, isLoggedIn } = useUserContext();
|
|
128
|
+
const [storageManaged, setStorageManaged] = useState(false);
|
|
129
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
130
|
+
|
|
131
|
+
// Generate unique instance ID to track operations and prevent race conditions
|
|
132
|
+
const instanceId = useRef(Math.random().toString(36).substring(7));
|
|
133
|
+
|
|
134
|
+
// Track if this instance has successfully restored data
|
|
135
|
+
const hasRestoredData = useRef(false);
|
|
136
|
+
|
|
137
|
+
const populateSessionFromUserData = (userKey) => {
|
|
138
|
+
const userData = localStorage.getItem(userKey);
|
|
139
|
+
if (userData) {
|
|
140
|
+
/* eslint-disable no-console */
|
|
141
|
+
console.log(
|
|
142
|
+
`[UserStorageManager:${instanceId.current}] Restoring from localStorage:`,
|
|
143
|
+
{
|
|
144
|
+
key: userKey,
|
|
145
|
+
dataPreview:
|
|
146
|
+
userData.substring(0, 100) + (userData.length > 100 ? '...' : ''),
|
|
147
|
+
dataLength: userData.length,
|
|
148
|
+
},
|
|
149
|
+
);
|
|
150
|
+
/* eslint-enable no-console */
|
|
151
|
+
const parsed = JSON.parse(userData);
|
|
152
|
+
const userIdFromKey = (key) => key.replace(/^user_/, '');
|
|
153
|
+
const hydratedFor = sessionStorage.getItem('mv_hydrated_for');
|
|
154
|
+
const alreadyHasLayers = (() => {
|
|
155
|
+
try {
|
|
156
|
+
const cl = JSON.parse(
|
|
157
|
+
sessionStorage.getItem('checkedLayers') || '[]',
|
|
158
|
+
);
|
|
159
|
+
return Array.isArray(cl) && cl.length > 0;
|
|
160
|
+
} catch {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
})();
|
|
164
|
+
if (hydratedFor === userIdFromKey(userKey) || alreadyHasLayers) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
Object.entries(parsed).forEach(([k, v]) => {
|
|
168
|
+
const existing = sessionStorage.getItem(k);
|
|
169
|
+
if (existing == null) {
|
|
170
|
+
sessionStorage.setItem(
|
|
171
|
+
k,
|
|
172
|
+
typeof v === 'object' ? JSON.stringify(v) : v,
|
|
173
|
+
);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (k === 'checkedLayers') {
|
|
177
|
+
try {
|
|
178
|
+
const a = JSON.parse(existing || '[]');
|
|
179
|
+
const b = typeof v === 'string' ? JSON.parse(v) : v;
|
|
180
|
+
const union = [...new Set([...(b || []), ...(a || [])])];
|
|
181
|
+
sessionStorage.setItem('checkedLayers', JSON.stringify(union));
|
|
182
|
+
} catch {}
|
|
183
|
+
} else if (k === 'visibleLayers' || k === 'layerOpacities') {
|
|
184
|
+
try {
|
|
185
|
+
const a = JSON.parse(existing || '{}');
|
|
186
|
+
const b = typeof v === 'string' ? JSON.parse(v) : v || {};
|
|
187
|
+
sessionStorage.setItem(k, JSON.stringify({ ...b, ...a }));
|
|
188
|
+
} catch {}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
sessionStorage.setItem('mv_hydrated_for', userIdFromKey(userKey));
|
|
192
|
+
|
|
193
|
+
// Mark that this instance has successfully restored data
|
|
194
|
+
hasRestoredData.current = true;
|
|
195
|
+
|
|
196
|
+
return true; // Indicate successful restoration
|
|
197
|
+
} else {
|
|
198
|
+
/* eslint-disable no-console */
|
|
199
|
+
console.log(
|
|
200
|
+
`[UserStorageManager:${instanceId.current}] No data found for key:`,
|
|
201
|
+
userKey,
|
|
202
|
+
);
|
|
203
|
+
/* eslint-enable no-console */
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// Improved instance management with lock mechanism to prevent race conditions
|
|
209
|
+
const acquireStorageLock = (lockKey) => {
|
|
210
|
+
const existingLock = localStorage.getItem(lockKey);
|
|
211
|
+
if (existingLock && existingLock !== instanceId.current) {
|
|
212
|
+
return false; // Another instance has the lock
|
|
213
|
+
}
|
|
214
|
+
localStorage.setItem(lockKey, instanceId.current);
|
|
215
|
+
return true;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const releaseStorageLock = (lockKey) => {
|
|
219
|
+
const currentLock = localStorage.getItem(lockKey);
|
|
220
|
+
if (currentLock === instanceId.current) {
|
|
221
|
+
localStorage.removeItem(lockKey);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Initialization effect - handles user state readiness
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
if (userID !== undefined && isLoggedIn !== undefined) {
|
|
228
|
+
/* eslint-disable no-console */
|
|
229
|
+
console.log(
|
|
230
|
+
`[UserStorageManager:${instanceId.current}] User state initialized:`,
|
|
231
|
+
{
|
|
232
|
+
userID,
|
|
233
|
+
isLoggedIn,
|
|
234
|
+
},
|
|
235
|
+
);
|
|
236
|
+
/* eslint-enable no-console */
|
|
237
|
+
setIsInitialized(true);
|
|
238
|
+
}
|
|
239
|
+
}, [userID, isLoggedIn]);
|
|
240
|
+
|
|
241
|
+
// Initial storage management effect - runs once on mount with lock protection
|
|
242
|
+
useEffect(() => {
|
|
243
|
+
if (!isInitialized || storageManaged) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const lockKey = `storage_lock_${userID || 'anonymous'}`;
|
|
248
|
+
|
|
249
|
+
/* eslint-disable no-console */
|
|
250
|
+
console.log(
|
|
251
|
+
`[UserStorageManager:${instanceId.current}] Component mounting with state:`,
|
|
252
|
+
{
|
|
253
|
+
isLoggedIn,
|
|
254
|
+
userID,
|
|
255
|
+
storageManaged,
|
|
256
|
+
isInitialized,
|
|
257
|
+
},
|
|
258
|
+
);
|
|
259
|
+
/* eslint-enable no-console */
|
|
260
|
+
|
|
261
|
+
// Acquire lock to prevent concurrent operations
|
|
262
|
+
if (!acquireStorageLock(lockKey)) {
|
|
263
|
+
/* eslint-disable no-console */
|
|
264
|
+
console.log(
|
|
265
|
+
`[UserStorageManager:${instanceId.current}] Another instance is managing storage for this user`,
|
|
266
|
+
);
|
|
267
|
+
/* eslint-enable no-console */
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
try {
|
|
271
|
+
if (isLoggedIn === true) {
|
|
272
|
+
/* eslint-disable no-console */
|
|
273
|
+
console.log(
|
|
274
|
+
`[UserStorageManager:${instanceId.current}] Detected signed-in user, processing storage...`,
|
|
275
|
+
);
|
|
276
|
+
/* eslint-enable no-console */
|
|
277
|
+
|
|
278
|
+
if (
|
|
279
|
+
userID &&
|
|
280
|
+
userID !== null &&
|
|
281
|
+
userID !== undefined &&
|
|
282
|
+
userID !== ''
|
|
283
|
+
) {
|
|
284
|
+
const userKey = `user_${userID}`;
|
|
285
|
+
const userData = localStorage.getItem(userKey);
|
|
286
|
+
const anonymousData = localStorage.getItem('user_anonymous');
|
|
287
|
+
|
|
288
|
+
/* eslint-disable no-console */
|
|
289
|
+
console.log(
|
|
290
|
+
`[UserStorageManager:${instanceId.current}] Storage analysis:`,
|
|
291
|
+
{
|
|
292
|
+
userKey,
|
|
293
|
+
hasUserData: !!userData,
|
|
294
|
+
hasAnonymousData: !!anonymousData,
|
|
295
|
+
sessionEmpty: sessionStorage.length === 0,
|
|
296
|
+
sessionLength: sessionStorage.length,
|
|
297
|
+
},
|
|
298
|
+
);
|
|
299
|
+
/* eslint-enable no-console */
|
|
300
|
+
|
|
301
|
+
// Migration and restoration logic for signed-in users
|
|
302
|
+
if (!userData && anonymousData) {
|
|
303
|
+
/* eslint-disable no-console */
|
|
304
|
+
console.log(
|
|
305
|
+
`[UserStorageManager:${instanceId.current}] Migrating anonymous data to signed-in user`,
|
|
306
|
+
);
|
|
307
|
+
/* eslint-enable no-console */
|
|
308
|
+
// Move anonymous data to the signed-in user's localStorage key
|
|
309
|
+
localStorage.setItem(userKey, anonymousData);
|
|
310
|
+
// Delete the anonymous key from localStorage
|
|
311
|
+
localStorage.removeItem('user_anonymous');
|
|
312
|
+
// Populate sessionStorage with the migrated data from localStorage
|
|
313
|
+
populateSessionFromUserData(userKey);
|
|
314
|
+
} else if (userData) {
|
|
315
|
+
/* eslint-disable no-console */
|
|
316
|
+
console.log(
|
|
317
|
+
`[UserStorageManager:${instanceId.current}] Found existing user data - restoring to session storage`,
|
|
318
|
+
);
|
|
319
|
+
/* eslint-enable no-console */
|
|
320
|
+
// User has existing saved data - restore it to sessionStorage
|
|
321
|
+
populateSessionFromUserData(userKey);
|
|
322
|
+
} else {
|
|
323
|
+
/* eslint-disable no-console */
|
|
324
|
+
console.log(
|
|
325
|
+
`[UserStorageManager:${instanceId.current}] No saved user data found - preserving current session state`,
|
|
326
|
+
);
|
|
327
|
+
/* eslint-enable no-console */
|
|
328
|
+
}
|
|
329
|
+
setStorageManaged(true);
|
|
330
|
+
} else {
|
|
331
|
+
/* eslint-disable no-console */
|
|
332
|
+
console.log(
|
|
333
|
+
`[UserStorageManager:${instanceId.current}] valid userID unavailable: userID is ${userID}`,
|
|
334
|
+
);
|
|
335
|
+
/* eslint-enable no-console */
|
|
336
|
+
}
|
|
337
|
+
} else if (isLoggedIn === false) {
|
|
338
|
+
/* eslint-disable no-console */
|
|
339
|
+
console.log(
|
|
340
|
+
`[UserStorageManager:${instanceId.current}] Detected anonymous user, processing storage...`,
|
|
341
|
+
);
|
|
342
|
+
/* eslint-enable no-console */
|
|
343
|
+
// Handle anonymous user session - restore anonymous data if it exists
|
|
344
|
+
const anonymousKey = 'user_anonymous';
|
|
345
|
+
const anonymousData = localStorage.getItem(anonymousKey);
|
|
346
|
+
if (anonymousData) {
|
|
347
|
+
/* eslint-disable no-console */
|
|
348
|
+
console.log(
|
|
349
|
+
`[UserStorageManager:${instanceId.current}] Restoring anonymous data to session storage:`,
|
|
350
|
+
{
|
|
351
|
+
dataPreview:
|
|
352
|
+
anonymousData.substring(0, 100) +
|
|
353
|
+
(anonymousData.length > 100 ? '...' : ''),
|
|
354
|
+
dataLength: anonymousData.length,
|
|
355
|
+
},
|
|
356
|
+
);
|
|
357
|
+
/* eslint-enable no-console */
|
|
358
|
+
sessionStorage.clear();
|
|
359
|
+
const parsed = JSON.parse(anonymousData);
|
|
360
|
+
Object.keys(parsed).forEach((k) =>
|
|
361
|
+
sessionStorage.setItem(
|
|
362
|
+
k,
|
|
363
|
+
typeof parsed[k] === 'object'
|
|
364
|
+
? JSON.stringify(parsed[k])
|
|
365
|
+
: parsed[k],
|
|
366
|
+
),
|
|
367
|
+
);
|
|
368
|
+
hasRestoredData.current = true;
|
|
369
|
+
/* eslint-disable no-console */
|
|
370
|
+
console.log(
|
|
371
|
+
`[UserStorageManager:${instanceId.current}] Anonymous data restored to sessionStorage`,
|
|
372
|
+
);
|
|
373
|
+
/* eslint-enable no-console */
|
|
374
|
+
} else {
|
|
375
|
+
/* eslint-disable no-console */
|
|
376
|
+
console.log(
|
|
377
|
+
`[UserStorageManager:${instanceId.current}] No anonymous data found to restore`,
|
|
378
|
+
);
|
|
379
|
+
/* eslint-enable no-console */
|
|
380
|
+
}
|
|
381
|
+
setStorageManaged(true);
|
|
382
|
+
} else {
|
|
383
|
+
/* eslint-disable no-console */
|
|
384
|
+
console.log(
|
|
385
|
+
`[UserStorageManager:${instanceId.current}] User state does not match any processing condition - skipping storage logic`,
|
|
386
|
+
);
|
|
387
|
+
/* eslint-enable no-console */
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (onStorageManaged) {
|
|
391
|
+
onStorageManaged();
|
|
392
|
+
}
|
|
393
|
+
} finally {
|
|
394
|
+
// Always release the lock, even if an error occurred
|
|
395
|
+
releaseStorageLock(lockKey);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Cleanup function to release lock on unmount
|
|
399
|
+
return () => {
|
|
400
|
+
releaseStorageLock(lockKey);
|
|
401
|
+
};
|
|
402
|
+
}, [isInitialized, isLoggedIn, userID, storageManaged, onStorageManaged]);
|
|
403
|
+
|
|
404
|
+
// Data-reactive effect - ensures sessionStorage mirrors localStorage whenever userData changes
|
|
405
|
+
// useEffect(() => {
|
|
406
|
+
// /* eslint-disable no-console */
|
|
407
|
+
// console.log(
|
|
408
|
+
// `[UserStorageManager:${instanceId.current}] Data-reactive effect triggered:`,
|
|
409
|
+
// {
|
|
410
|
+
// storageManaged,
|
|
411
|
+
// userKey: userKey,
|
|
412
|
+
// hasUserData: !!userData,
|
|
413
|
+
// userDataLength: userData ? userData.length : 0,
|
|
414
|
+
// },
|
|
415
|
+
// );
|
|
416
|
+
// /* eslint-enable no-console */
|
|
417
|
+
|
|
418
|
+
// if (storageManaged && userKey && userData) {
|
|
419
|
+
// /* eslint-disable no-console */
|
|
420
|
+
// console.log(
|
|
421
|
+
// `[UserStorageManager:${instanceId.current}] Re-syncing session storage with localStorage changes`,
|
|
422
|
+
// );
|
|
423
|
+
// /* eslint-enable no-console */
|
|
424
|
+
// populateSessionFromUserData(userKey);
|
|
425
|
+
// } else {
|
|
426
|
+
// /* eslint-disable no-console */
|
|
427
|
+
// console.log(
|
|
428
|
+
// `[UserStorageManager:${instanceId.current}] Skipping data sync - conditions not met`,
|
|
429
|
+
// );
|
|
430
|
+
// /* eslint-enable no-console */
|
|
431
|
+
// }
|
|
432
|
+
// }, [userData, userKey, storageManaged]);
|
|
433
|
+
|
|
434
|
+
// Render only when properly initialized to prevent premature mounting
|
|
435
|
+
return isInitialized &&
|
|
436
|
+
storageManaged &&
|
|
437
|
+
userID !== undefined &&
|
|
438
|
+
isLoggedIn !== undefined ? (
|
|
439
|
+
children
|
|
440
|
+
) : (
|
|
441
|
+
<div className="loading-container">
|
|
442
|
+
<div className="loading-text">Loading...</div>
|
|
443
|
+
</div>
|
|
444
|
+
);
|
|
445
|
+
};
|
|
446
|
+
|
|
37
447
|
class MapViewer extends React.Component {
|
|
448
|
+
static contextType = UserContext;
|
|
449
|
+
|
|
38
450
|
/**
|
|
39
451
|
* This method does the creation of the main component
|
|
40
452
|
* @param {*} props
|
|
@@ -56,18 +468,28 @@ class MapViewer extends React.Component {
|
|
|
56
468
|
this.mapClass = classNames('map-container', {
|
|
57
469
|
[`${props.customClass}`]: props.customClass || null,
|
|
58
470
|
});
|
|
471
|
+
|
|
472
|
+
// Generate unique instance ID for tracking operations
|
|
473
|
+
this.instanceId = Math.random().toString(36).substring(7);
|
|
474
|
+
|
|
59
475
|
this.state = {
|
|
60
476
|
layerLoading: false,
|
|
61
477
|
layers: {},
|
|
62
478
|
uploadedFile: true,
|
|
63
479
|
wmsServiceUrl: '',
|
|
64
480
|
uploadError: false,
|
|
481
|
+
// Track current user state for comparison in componentDidUpdate
|
|
482
|
+
currentUserState: props.initialUserState || {
|
|
483
|
+
user_id: null,
|
|
484
|
+
isLoggedIn: false,
|
|
485
|
+
},
|
|
65
486
|
};
|
|
66
487
|
this.activeLayersHandler = this.activeLayersHandler.bind(this);
|
|
67
488
|
this.activeLayersArray = {};
|
|
68
489
|
this.props.mapviewer_config.loading = true;
|
|
69
490
|
this.cfgUrls = this.props.cfg.Urls;
|
|
70
|
-
|
|
491
|
+
// User state change handler
|
|
492
|
+
this.handleUserStateChange = this.handleUserStateChange.bind(this);
|
|
71
493
|
this.loadingHandler = this.loadingHandler.bind(this);
|
|
72
494
|
this.hotspotDataHandler = this.hotspotDataHandler.bind(this);
|
|
73
495
|
this.mapLayersHandler = this.mapLayersHandler.bind(this);
|
|
@@ -80,6 +502,285 @@ class MapViewer extends React.Component {
|
|
|
80
502
|
this.tax = null;
|
|
81
503
|
}
|
|
82
504
|
|
|
505
|
+
// Method to handle user state changes from the monitoring wrapper
|
|
506
|
+
handleUserStateChange(newUserState, previousUserState) {
|
|
507
|
+
/* eslint-disable no-console */
|
|
508
|
+
console.log('[MapViewer] Handling user state change:', {
|
|
509
|
+
newUserState,
|
|
510
|
+
previousUserState,
|
|
511
|
+
currentState: this.state.currentUserState,
|
|
512
|
+
});
|
|
513
|
+
/* eslint-enable no-console */
|
|
514
|
+
|
|
515
|
+
// Update current user state in component state
|
|
516
|
+
this.setState({ currentUserState: newUserState });
|
|
517
|
+
|
|
518
|
+
// Trigger session state update logic
|
|
519
|
+
this.handleSessionStateUpdate(newUserState, previousUserState);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Enhanced method to save session data to localStorage with instance tracking
|
|
523
|
+
saveSessionToLocalStorage = () => {
|
|
524
|
+
const { user_id, isLoggedIn } = this.context;
|
|
525
|
+
const instanceId = this.instanceId || 'unknown';
|
|
526
|
+
|
|
527
|
+
/* eslint-disable no-console */
|
|
528
|
+
console.log(`[MapViewer:${instanceId}] Saving session data:`, {
|
|
529
|
+
hasUserContext:
|
|
530
|
+
user_id !== undefined && user_id !== null && user_id !== '',
|
|
531
|
+
isLoggedIn,
|
|
532
|
+
userId:
|
|
533
|
+
user_id !== undefined && user_id !== null && user_id !== ''
|
|
534
|
+
? user_id
|
|
535
|
+
: 'anonymous',
|
|
536
|
+
sessionStorageLength: sessionStorage.length,
|
|
537
|
+
});
|
|
538
|
+
/* eslint-enable no-console */
|
|
539
|
+
|
|
540
|
+
if (sessionStorage.length === 0) {
|
|
541
|
+
/* eslint-disable no-console */
|
|
542
|
+
console.log(
|
|
543
|
+
`[MapViewer:${instanceId}] Skipping data save - session storage is empty`,
|
|
544
|
+
);
|
|
545
|
+
/* eslint-enable no-console */
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const saveToLocal = (key) => {
|
|
550
|
+
const data = {};
|
|
551
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
552
|
+
const k = sessionStorage.key(i);
|
|
553
|
+
data[k] = sessionStorage.getItem(k);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
try {
|
|
557
|
+
localStorage.setItem(key, JSON.stringify(data));
|
|
558
|
+
/* eslint-disable no-console */
|
|
559
|
+
console.log(
|
|
560
|
+
`[MapViewer:${instanceId}] Successfully saved data to localStorage key: ${key}`,
|
|
561
|
+
);
|
|
562
|
+
/* eslint-enable no-console */
|
|
563
|
+
} catch (error) {
|
|
564
|
+
/* eslint-disable no-console */
|
|
565
|
+
console.error(
|
|
566
|
+
`[MapViewer:${instanceId}] Error saving to localStorage key ${key}:`,
|
|
567
|
+
error,
|
|
568
|
+
);
|
|
569
|
+
/* eslint-enable no-console */
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
// Save session data to appropriate localStorage key based on user state (always overwrite user key)
|
|
574
|
+
if (
|
|
575
|
+
isLoggedIn &&
|
|
576
|
+
user_id !== undefined &&
|
|
577
|
+
user_id !== null &&
|
|
578
|
+
user_id !== ''
|
|
579
|
+
) {
|
|
580
|
+
if (localStorage.getItem(`user_${user_id}`)) {
|
|
581
|
+
/* eslint-disable no-console */
|
|
582
|
+
console.log(
|
|
583
|
+
`[MapViewer:${instanceId}] User session data already exists in localStorage`,
|
|
584
|
+
);
|
|
585
|
+
/* eslint-enable no-console */
|
|
586
|
+
}
|
|
587
|
+
saveToLocal(`user_${user_id}`);
|
|
588
|
+
} else if (!isLoggedIn) {
|
|
589
|
+
saveToLocal('user_anonymous');
|
|
590
|
+
}
|
|
591
|
+
sessionStorage.clear();
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
// Handle page unload events (navigation, refresh, close)
|
|
595
|
+
handlePageUnload = (event) => {
|
|
596
|
+
/* eslint-disable no-console */
|
|
597
|
+
console.log(
|
|
598
|
+
`[MapViewer:${this.instanceId}] Page unload detected, saving session data`,
|
|
599
|
+
);
|
|
600
|
+
/* eslint-enable no-console */
|
|
601
|
+
|
|
602
|
+
this.saveSessionToLocalStorage();
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
// Handle visibility changes (tab switches, window minimizing)
|
|
606
|
+
handleVisibilityChange = () => {
|
|
607
|
+
if (document.visibilityState === 'hidden') {
|
|
608
|
+
/* eslint-disable no-console */
|
|
609
|
+
console.log(
|
|
610
|
+
`[MapViewer:${this.instanceId}] Page hidden, saving session data`,
|
|
611
|
+
);
|
|
612
|
+
/* eslint-enable no-console */
|
|
613
|
+
|
|
614
|
+
this.saveSessionToLocalStorage();
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
// Method to handle session state updates when user authentication changes
|
|
619
|
+
handleSessionStateUpdate(newUserState, previousUserState) {
|
|
620
|
+
const { user_id: newUserId, isLoggedIn: newIsLoggedIn } = newUserState;
|
|
621
|
+
const {
|
|
622
|
+
user_id: prevUserId,
|
|
623
|
+
isLoggedIn: prevIsLoggedIn,
|
|
624
|
+
} = previousUserState;
|
|
625
|
+
|
|
626
|
+
/* eslint-disable no-console */
|
|
627
|
+
console.log('[MapViewer] Processing session state update:', {
|
|
628
|
+
userIdChanged: prevUserId !== newUserId,
|
|
629
|
+
loginStateChanged: prevIsLoggedIn !== newIsLoggedIn,
|
|
630
|
+
loginTransition: `${prevIsLoggedIn} -> ${newIsLoggedIn}`,
|
|
631
|
+
userIdTransition: `${prevUserId} -> ${newUserId}`,
|
|
632
|
+
});
|
|
633
|
+
/* eslint-enable no-console */
|
|
634
|
+
|
|
635
|
+
// Handle login/logout transitions
|
|
636
|
+
if (prevIsLoggedIn !== newIsLoggedIn) {
|
|
637
|
+
if (newIsLoggedIn && !prevIsLoggedIn) {
|
|
638
|
+
// User just logged in
|
|
639
|
+
this.handleUserLogin(newUserId);
|
|
640
|
+
} else if (!newIsLoggedIn && prevIsLoggedIn) {
|
|
641
|
+
// User just logged out
|
|
642
|
+
this.handleUserLogout(prevUserId);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Handle user ID changes (e.g., switching accounts)
|
|
647
|
+
if (prevUserId !== newUserId && newIsLoggedIn) {
|
|
648
|
+
this.handleUserSwitch(prevUserId, newUserId);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Handle user login - restore saved session or preserve current session
|
|
653
|
+
handleUserLogin(userId) {
|
|
654
|
+
/* eslint-disable no-console */
|
|
655
|
+
console.log('[MapViewer] User logged in:', userId);
|
|
656
|
+
/* eslint-enable no-console */
|
|
657
|
+
|
|
658
|
+
// Check if user has saved data
|
|
659
|
+
const userKey = `user_${userId}`;
|
|
660
|
+
const userData = localStorage.getItem(userKey);
|
|
661
|
+
|
|
662
|
+
if (userData) {
|
|
663
|
+
/* eslint-disable no-console */
|
|
664
|
+
console.log('[MapViewer] Restoring saved user session data');
|
|
665
|
+
/* eslint-enable no-console */
|
|
666
|
+
// Restore user's saved session
|
|
667
|
+
try {
|
|
668
|
+
const parsed = JSON.parse(userData);
|
|
669
|
+
Object.keys(parsed).forEach((k) =>
|
|
670
|
+
sessionStorage.setItem(
|
|
671
|
+
k,
|
|
672
|
+
typeof parsed[k] === 'object'
|
|
673
|
+
? JSON.stringify(parsed[k])
|
|
674
|
+
: parsed[k],
|
|
675
|
+
),
|
|
676
|
+
);
|
|
677
|
+
} catch (error) {
|
|
678
|
+
/* eslint-disable no-console */
|
|
679
|
+
console.error('[MapViewer] Error restoring user session:', error);
|
|
680
|
+
/* eslint-enable no-console */
|
|
681
|
+
}
|
|
682
|
+
} else {
|
|
683
|
+
/* eslint-disable no-console */
|
|
684
|
+
console.log(
|
|
685
|
+
'[MapViewer] No saved session found - preserving current session',
|
|
686
|
+
);
|
|
687
|
+
/* eslint-enable no-console */
|
|
688
|
+
// No saved data - preserve current session state
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// Handle user logout - save current session to anonymous storage
|
|
693
|
+
handleUserLogout(prevUserId) {
|
|
694
|
+
/* eslint-disable no-console */
|
|
695
|
+
console.log('[MapViewer] User logged out:', prevUserId);
|
|
696
|
+
/* eslint-enable no-console */
|
|
697
|
+
|
|
698
|
+
// Save current session to anonymous storage
|
|
699
|
+
const sessionContents = {};
|
|
700
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
701
|
+
const key = sessionStorage.key(i);
|
|
702
|
+
sessionContents[key] = sessionStorage.getItem(key);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (Object.keys(sessionContents).length > 0) {
|
|
706
|
+
// Persist snapshot under previous user key first (if available)
|
|
707
|
+
if (prevUserId) {
|
|
708
|
+
try {
|
|
709
|
+
localStorage.setItem(
|
|
710
|
+
`user_${prevUserId}`,
|
|
711
|
+
JSON.stringify(sessionContents),
|
|
712
|
+
);
|
|
713
|
+
/* eslint-disable no-console */
|
|
714
|
+
console.log(
|
|
715
|
+
'[MapViewer] Saved session to previous user key before logout',
|
|
716
|
+
);
|
|
717
|
+
/* eslint-enable no-console */
|
|
718
|
+
} catch (error) {
|
|
719
|
+
/* eslint-disable no-console */
|
|
720
|
+
console.error(
|
|
721
|
+
'[MapViewer] Error saving previous user session on logout:',
|
|
722
|
+
error,
|
|
723
|
+
);
|
|
724
|
+
/* eslint-enable no-console */
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
try {
|
|
728
|
+
localStorage.setItem('user_anonymous', JSON.stringify(sessionContents));
|
|
729
|
+
/* eslint-disable no-console */
|
|
730
|
+
console.log('[MapViewer] Saved session to anonymous storage');
|
|
731
|
+
/* eslint-enable no-console */
|
|
732
|
+
} catch (error) {
|
|
733
|
+
/* eslint-disable no-console */
|
|
734
|
+
console.error('[MapViewer] Error saving anonymous session:', error);
|
|
735
|
+
/* eslint-enable no-console */
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// Handle user account switching
|
|
741
|
+
handleUserSwitch(prevUserId, newUserId) {
|
|
742
|
+
/* eslint-disable no-console */
|
|
743
|
+
console.log('[MapViewer] User switched accounts:', {
|
|
744
|
+
prevUserId,
|
|
745
|
+
newUserId,
|
|
746
|
+
});
|
|
747
|
+
/* eslint-enable no-console */
|
|
748
|
+
|
|
749
|
+
// Save current session to previous user's storage
|
|
750
|
+
if (prevUserId) {
|
|
751
|
+
const sessionContents = {};
|
|
752
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
753
|
+
const key = sessionStorage.key(i);
|
|
754
|
+
sessionContents[key] = sessionStorage.getItem(key);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
if (Object.keys(sessionContents).length > 0) {
|
|
758
|
+
try {
|
|
759
|
+
localStorage.setItem(
|
|
760
|
+
`user_${prevUserId}`,
|
|
761
|
+
JSON.stringify(sessionContents),
|
|
762
|
+
);
|
|
763
|
+
/* eslint-disable no-console */
|
|
764
|
+
console.log(
|
|
765
|
+
'[MapViewer] Saved session for previous user:',
|
|
766
|
+
prevUserId,
|
|
767
|
+
);
|
|
768
|
+
/* eslint-enable no-console */
|
|
769
|
+
} catch (error) {
|
|
770
|
+
/* eslint-disable no-console */
|
|
771
|
+
console.error(
|
|
772
|
+
'[MapViewer] Error saving previous user session:',
|
|
773
|
+
error,
|
|
774
|
+
);
|
|
775
|
+
/* eslint-enable no-console */
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// Load new user's session
|
|
781
|
+
this.handleUserLogin(newUserId);
|
|
782
|
+
}
|
|
783
|
+
|
|
83
784
|
mapLayersHandler(newLayers) {
|
|
84
785
|
this.setState({ layers: newLayers });
|
|
85
786
|
}
|
|
@@ -249,13 +950,41 @@ class MapViewer extends React.Component {
|
|
|
249
950
|
logo: false,
|
|
250
951
|
});
|
|
251
952
|
|
|
953
|
+
/* eslint-disable no-console */
|
|
954
|
+
console.log(
|
|
955
|
+
`[MapViewer:${this.instanceId}] Attempting to recover map state from sessionStorage`,
|
|
956
|
+
);
|
|
957
|
+
/* eslint-enable no-console */
|
|
958
|
+
|
|
252
959
|
mapStatus = this.recoverState();
|
|
253
960
|
|
|
961
|
+
/* eslint-disable no-console */
|
|
962
|
+
console.log(`[MapViewer:${this.instanceId}] Recovered mapStatus:`, {
|
|
963
|
+
isNull: mapStatus === null,
|
|
964
|
+
isUndefined: mapStatus === undefined,
|
|
965
|
+
type: typeof mapStatus,
|
|
966
|
+
hasZoom: mapStatus && mapStatus.zoom !== undefined,
|
|
967
|
+
hasCenter: mapStatus && mapStatus.center !== undefined,
|
|
968
|
+
entryCount: mapStatus ? Object.entries(mapStatus).length : 0,
|
|
969
|
+
mapStatus: mapStatus,
|
|
970
|
+
});
|
|
971
|
+
/* eslint-enable no-console */
|
|
972
|
+
|
|
973
|
+
// Improved condition check to prevent false positives that overwrite restored data
|
|
254
974
|
if (
|
|
255
975
|
mapStatus === null ||
|
|
256
|
-
|
|
257
|
-
|
|
976
|
+
mapStatus === undefined ||
|
|
977
|
+
(typeof mapStatus === 'object' &&
|
|
978
|
+
mapStatus.zoom === undefined &&
|
|
979
|
+
mapStatus.center === undefined) ||
|
|
980
|
+
(typeof mapStatus === 'object' && Object.entries(mapStatus).length === 0)
|
|
258
981
|
) {
|
|
982
|
+
/* eslint-disable no-console */
|
|
983
|
+
console.log(
|
|
984
|
+
`[MapViewer:${this.instanceId}] No valid map state found - initializing with default configuration`,
|
|
985
|
+
);
|
|
986
|
+
/* eslint-enable no-console */
|
|
987
|
+
|
|
259
988
|
mapStatus = {};
|
|
260
989
|
mapStatus.zoom = this.mapCfg.zoom;
|
|
261
990
|
mapStatus.center = this.mapCfg.center;
|
|
@@ -263,6 +992,12 @@ class MapViewer extends React.Component {
|
|
|
263
992
|
this.setCenterState(this.mapCfg.center);
|
|
264
993
|
this.setZoomState(this.mapCfg.zoom);
|
|
265
994
|
this.activeLayersHandler(this.mapCfg.activeLayers);
|
|
995
|
+
} else {
|
|
996
|
+
/* eslint-disable no-console */
|
|
997
|
+
console.log(
|
|
998
|
+
`[MapViewer:${this.instanceId}] Using restored map state from sessionStorage`,
|
|
999
|
+
);
|
|
1000
|
+
/* eslint-enable no-console */
|
|
266
1001
|
}
|
|
267
1002
|
|
|
268
1003
|
this.view = new MapView({
|
|
@@ -320,15 +1055,26 @@ class MapViewer extends React.Component {
|
|
|
320
1055
|
// we will have stored the json response here:
|
|
321
1056
|
// this.props.mapviewer_config
|
|
322
1057
|
this.props.MapViewerConfig(flattenToAppURL(this.props.url));
|
|
323
|
-
|
|
324
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
1058
|
+
|
|
1059
|
+
// Add event listeners for page unload events to ensure data is saved
|
|
1060
|
+
/* eslint-disable no-console */
|
|
1061
|
+
console.log(
|
|
1062
|
+
`[MapViewer:${this.instanceId}] Adding page unload event listeners`,
|
|
1063
|
+
);
|
|
1064
|
+
/* eslint-enable no-console */
|
|
1065
|
+
|
|
1066
|
+
// beforeunload - most reliable for catching navigation away from page
|
|
1067
|
+
window.addEventListener('beforeunload', this.handlePageUnload);
|
|
1068
|
+
|
|
1069
|
+
// pagehide - more reliable than unload, catches all page hiding scenarios
|
|
1070
|
+
window.addEventListener('pagehide', this.handlePageUnload);
|
|
1071
|
+
|
|
1072
|
+
// visibilitychange - catches tab switches and window minimizing
|
|
1073
|
+
document.addEventListener('visibilitychange', this.handleVisibilityChange);
|
|
329
1074
|
}
|
|
330
1075
|
|
|
331
1076
|
componentDidUpdate(prevProps, prevState) {
|
|
1077
|
+
// Handle Download/dataset URL changes (existing logic)
|
|
332
1078
|
if (
|
|
333
1079
|
this.props.Download ||
|
|
334
1080
|
(this.location &&
|
|
@@ -341,17 +1087,63 @@ class MapViewer extends React.Component {
|
|
|
341
1087
|
}
|
|
342
1088
|
sessionStorage.setItem('toc_panel_scrolls', toc_panel_scrolls);
|
|
343
1089
|
}
|
|
344
|
-
|
|
345
|
-
//
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
1090
|
+
|
|
1091
|
+
// Handle user state changes from context
|
|
1092
|
+
const {
|
|
1093
|
+
user_id: currentUserId,
|
|
1094
|
+
isLoggedIn: currentIsLoggedIn,
|
|
1095
|
+
} = this.context;
|
|
1096
|
+
const { currentUserState: prevUserState } = prevState;
|
|
1097
|
+
|
|
1098
|
+
// Compare current context values with previous state
|
|
1099
|
+
if (
|
|
1100
|
+
prevUserState.user_id !== currentUserId ||
|
|
1101
|
+
prevUserState.isLoggedIn !== currentIsLoggedIn
|
|
1102
|
+
) {
|
|
1103
|
+
/* eslint-disable no-console */
|
|
1104
|
+
console.log(
|
|
1105
|
+
'[MapViewer] User state change detected in componentDidUpdate:',
|
|
1106
|
+
{
|
|
1107
|
+
previous: prevUserState,
|
|
1108
|
+
current: { user_id: currentUserId, isLoggedIn: currentIsLoggedIn },
|
|
1109
|
+
},
|
|
1110
|
+
);
|
|
1111
|
+
/* eslint-enable no-console */
|
|
1112
|
+
|
|
1113
|
+
// Update component state to reflect new user state
|
|
1114
|
+
const newUserState = {
|
|
1115
|
+
user_id: currentUserId,
|
|
1116
|
+
isLoggedIn: currentIsLoggedIn,
|
|
1117
|
+
};
|
|
1118
|
+
this.setState({ currentUserState: newUserState });
|
|
1119
|
+
|
|
1120
|
+
// Handle the user state change
|
|
1121
|
+
this.handleSessionStateUpdate(newUserState, prevUserState);
|
|
1122
|
+
}
|
|
351
1123
|
}
|
|
352
1124
|
|
|
353
1125
|
componentWillUnmount() {
|
|
354
|
-
//
|
|
1126
|
+
// Remove event listeners to prevent memory leaks
|
|
1127
|
+
/* eslint-disable no-console */
|
|
1128
|
+
console.log(`[MapViewer:${this.instanceId}] Removing event listeners`);
|
|
1129
|
+
/* eslint-enable no-console */
|
|
1130
|
+
|
|
1131
|
+
window.removeEventListener('beforeunload', this.handlePageUnload);
|
|
1132
|
+
window.removeEventListener('pagehide', this.handlePageUnload);
|
|
1133
|
+
document.removeEventListener(
|
|
1134
|
+
'visibilitychange',
|
|
1135
|
+
this.handleVisibilityChange,
|
|
1136
|
+
);
|
|
1137
|
+
|
|
1138
|
+
// Save data using the extracted method
|
|
1139
|
+
this.saveSessionToLocalStorage();
|
|
1140
|
+
|
|
1141
|
+
/* eslint-disable no-console */
|
|
1142
|
+
console.log(
|
|
1143
|
+
`[MapViewer:${this.instanceId}] Clearing session storage and cleaning up view`,
|
|
1144
|
+
);
|
|
1145
|
+
/* eslint-enable no-console */
|
|
1146
|
+
|
|
355
1147
|
if (this.view) {
|
|
356
1148
|
this.view.container = null;
|
|
357
1149
|
this.view.destroy();
|
|
@@ -554,7 +1346,7 @@ class MapViewer extends React.Component {
|
|
|
554
1346
|
if ('loading' in this.props.mapviewer_config) {
|
|
555
1347
|
return (
|
|
556
1348
|
<div className={this.mapClass}>
|
|
557
|
-
<div ref={this.mapdiv} className="map"
|
|
1349
|
+
<div ref={this.mapdiv} className="map" />
|
|
558
1350
|
</div>
|
|
559
1351
|
);
|
|
560
1352
|
} else {
|
|
@@ -572,10 +1364,8 @@ class MapViewer extends React.Component {
|
|
|
572
1364
|
{this.renderScale()}
|
|
573
1365
|
{this.renderInfo()}
|
|
574
1366
|
{this.renderHotspot()}
|
|
575
|
-
{/*this.renderMenu()*/}
|
|
576
|
-
{/*this.renderBookmark()*/}
|
|
577
|
-
<CheckUserID reference={this} />
|
|
578
1367
|
{this.renderLoadingSpinner()}
|
|
1368
|
+
<CheckUserID reference={this} />
|
|
579
1369
|
{this.renderUploadService()}
|
|
580
1370
|
</div>
|
|
581
1371
|
</div>
|
|
@@ -584,8 +1374,10 @@ class MapViewer extends React.Component {
|
|
|
584
1374
|
}
|
|
585
1375
|
}
|
|
586
1376
|
|
|
1377
|
+
// CheckLogin, CheckUserID now use useUserContext instead of useCartState
|
|
1378
|
+
|
|
587
1379
|
export const CheckLogin = ({ reference }) => {
|
|
588
|
-
|
|
1380
|
+
const { isLoggedIn } = useUserContext();
|
|
589
1381
|
return (
|
|
590
1382
|
<>
|
|
591
1383
|
{isLoggedIn && (
|
|
@@ -606,9 +1398,9 @@ export const CheckLogin = ({ reference }) => {
|
|
|
606
1398
|
</>
|
|
607
1399
|
);
|
|
608
1400
|
};
|
|
609
|
-
export const CheckUserID = ({ reference }) => {
|
|
610
|
-
let { user_id } = useCartState();
|
|
611
1401
|
|
|
1402
|
+
export const CheckUserID = ({ reference }) => {
|
|
1403
|
+
const { user_id, isLoggedIn } = useUserContext();
|
|
612
1404
|
return (
|
|
613
1405
|
<>
|
|
614
1406
|
{reference.view && (
|
|
@@ -653,6 +1445,7 @@ export const CheckUserID = ({ reference }) => {
|
|
|
653
1445
|
onServiceChange={reference.serviceChangeHandler}
|
|
654
1446
|
uploadFileErrorHandler={reference.uploadFileErrorHandler}
|
|
655
1447
|
userID={user_id}
|
|
1448
|
+
isLoggedIn={isLoggedIn}
|
|
656
1449
|
getTaxonomy={reference.getTaxonomy}
|
|
657
1450
|
tax={reference.tax}
|
|
658
1451
|
/>
|
|
@@ -661,10 +1454,47 @@ export const CheckUserID = ({ reference }) => {
|
|
|
661
1454
|
</>
|
|
662
1455
|
);
|
|
663
1456
|
};
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
1457
|
+
|
|
1458
|
+
const mapDispatchToProps = (dispatch) => ({
|
|
1459
|
+
getTaxonomy: (name) => dispatch(getTaxonomy(name)),
|
|
1460
|
+
});
|
|
1461
|
+
|
|
1462
|
+
const MapViewerWithProvider = (props) => {
|
|
1463
|
+
const mapViewerRef = useRef(null);
|
|
1464
|
+
const cartState = useCartState();
|
|
1465
|
+
|
|
1466
|
+
// Get initial user state
|
|
1467
|
+
const initialUserState = {
|
|
1468
|
+
user_id: cartState?.user_id || null,
|
|
1469
|
+
isLoggedIn: cartState?.isLoggedIn || false,
|
|
667
1470
|
};
|
|
1471
|
+
|
|
1472
|
+
// Handle user state changes from the monitor
|
|
1473
|
+
const handleUserStateChange = useCallback(
|
|
1474
|
+
(newUserState, previousUserState) => {
|
|
1475
|
+
if (mapViewerRef.current) {
|
|
1476
|
+
mapViewerRef.current.handleUserStateChange(
|
|
1477
|
+
newUserState,
|
|
1478
|
+
previousUserState,
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1481
|
+
},
|
|
1482
|
+
[],
|
|
1483
|
+
);
|
|
1484
|
+
|
|
1485
|
+
return (
|
|
1486
|
+
<UserProvider>
|
|
1487
|
+
<UserStorageManager>
|
|
1488
|
+
<MapViewerStateMonitor onUserStateChange={handleUserStateChange}>
|
|
1489
|
+
<MapViewer
|
|
1490
|
+
{...props}
|
|
1491
|
+
ref={mapViewerRef}
|
|
1492
|
+
initialUserState={initialUserState}
|
|
1493
|
+
/>
|
|
1494
|
+
</MapViewerStateMonitor>
|
|
1495
|
+
</UserStorageManager>
|
|
1496
|
+
</UserProvider>
|
|
1497
|
+
);
|
|
668
1498
|
};
|
|
669
1499
|
|
|
670
1500
|
export default compose(
|
|
@@ -676,4 +1506,4 @@ export default compose(
|
|
|
676
1506
|
),
|
|
677
1507
|
connect(null, mapDispatchToProps),
|
|
678
1508
|
injectLazyLibs('highcharts'),
|
|
679
|
-
)(
|
|
1509
|
+
)(MapViewerWithProvider, MenuWidget);
|
|
@@ -1093,7 +1093,6 @@ class MenuWidget extends React.Component {
|
|
|
1093
1093
|
let button = familyDropdown.querySelector(
|
|
1094
1094
|
'.ccl-expandable__button',
|
|
1095
1095
|
);
|
|
1096
|
-
scrollPosition = familyDropdown.offsetTop;
|
|
1097
1096
|
if (button) {
|
|
1098
1097
|
button.setAttribute('aria-expanded', 'true');
|
|
1099
1098
|
}
|
|
@@ -1107,6 +1106,9 @@ class MenuWidget extends React.Component {
|
|
|
1107
1106
|
button.setAttribute('aria-expanded', 'true');
|
|
1108
1107
|
}
|
|
1109
1108
|
}
|
|
1109
|
+
if (familyDropdown) {
|
|
1110
|
+
scrollPosition = familyDropdown.offsetTop;
|
|
1111
|
+
}
|
|
1110
1112
|
let mapMenu = node.closest('.map-menu-dataset-dropdown');
|
|
1111
1113
|
if (mapMenu) {
|
|
1112
1114
|
scrollPosition = mapMenu.offsetTop;
|
|
@@ -2318,6 +2320,7 @@ class MenuWidget extends React.Component {
|
|
|
2318
2320
|
this.props.uploadFileErrorHandler();
|
|
2319
2321
|
return;
|
|
2320
2322
|
}
|
|
2323
|
+
} else {
|
|
2321
2324
|
}
|
|
2322
2325
|
}
|
|
2323
2326
|
|
|
@@ -2435,7 +2438,7 @@ class MenuWidget extends React.Component {
|
|
|
2435
2438
|
}
|
|
2436
2439
|
|
|
2437
2440
|
saveUserServicesToStorage(layers) {
|
|
2438
|
-
if (this.userID
|
|
2441
|
+
if (this.userID === null) return;
|
|
2439
2442
|
|
|
2440
2443
|
try {
|
|
2441
2444
|
const layersToSave = layers.map((layer) => {
|
|
@@ -2478,8 +2481,7 @@ class MenuWidget extends React.Component {
|
|
|
2478
2481
|
}
|
|
2479
2482
|
|
|
2480
2483
|
async loadUserServicesFromStorage() {
|
|
2481
|
-
if (this.userID
|
|
2482
|
-
sessionStorage.clear();
|
|
2484
|
+
if (this.userID !== null) {
|
|
2483
2485
|
try {
|
|
2484
2486
|
const savedServices = JSON.parse(
|
|
2485
2487
|
localStorage.getItem(USER_SERVICES_KEY + '_' + this.userID),
|
|
@@ -3362,33 +3364,24 @@ class MenuWidget extends React.Component {
|
|
|
3362
3364
|
try {
|
|
3363
3365
|
const response = await fetch(`${subLayer.url}?f=pjson`);
|
|
3364
3366
|
if (!response.ok) {
|
|
3365
|
-
|
|
3366
|
-
continue; // Skip this iteration on error
|
|
3367
|
+
continue;
|
|
3367
3368
|
}
|
|
3368
|
-
const subLayerData = await response.json();
|
|
3369
|
+
const subLayerData = await response.json();
|
|
3369
3370
|
if (subLayerData === null) {
|
|
3370
|
-
//console.log('no data retrieved:', subLayerData);
|
|
3371
3371
|
continue;
|
|
3372
3372
|
} else {
|
|
3373
|
-
// Convert bounding box data to correct extent values for map view
|
|
3374
|
-
|
|
3375
3373
|
let extent = this.convertBBOXValues(subLayerData.extent);
|
|
3376
|
-
|
|
3377
|
-
// Store sublayer extent
|
|
3378
|
-
|
|
3379
3374
|
BBoxes[subLayerData.name] = {
|
|
3380
3375
|
id: subLayerData.id,
|
|
3381
3376
|
extent: extent,
|
|
3382
3377
|
};
|
|
3383
3378
|
}
|
|
3384
|
-
} catch (error) {
|
|
3385
|
-
//console.error('Error fetching sublayer:', error);
|
|
3386
|
-
}
|
|
3379
|
+
} catch (error) {}
|
|
3387
3380
|
}
|
|
3388
3381
|
|
|
3389
3382
|
BBoxes['dataset'] = this.convertBBOXValues(layer?.fullExtent?.extent);
|
|
3390
3383
|
|
|
3391
|
-
return BBoxes;
|
|
3384
|
+
return BBoxes;
|
|
3392
3385
|
}
|
|
3393
3386
|
|
|
3394
3387
|
parseBBOXWMS(xml) {
|