react-session.manager.sk 2.0.1 → 2.0.2

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.
@@ -17,3 +17,12 @@
17
17
  * This source code is licensed under the MIT license found in the
18
18
  * LICENSE file in the root directory of this source tree.
19
19
  */
20
+
21
+ /** @license React v16.13.1
22
+ * react-is.production.min.js
23
+ *
24
+ * Copyright (c) Facebook, Inc. and its affiliates.
25
+ *
26
+ * This source code is licensed under the MIT license found in the
27
+ * LICENSE file in the root directory of this source tree.
28
+ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-session.manager.sk",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "A react component used to manage token sessions with flask backend",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -21,15 +21,23 @@ class ErrorBoundary extends React.Component {
21
21
  errorInfo: errorInfo,
22
22
  });
23
23
 
24
+ // Check if this is a theme-related error
25
+ const isThemeError =
26
+ error?.message?.includes("Cannot convert undefined or null to object") &&
27
+ (error?.stack?.includes("Object.entries") ||
28
+ error?.stack?.includes("theme") ||
29
+ error?.stack?.includes("Styled"));
30
+
31
+ const errorMessage = isThemeError
32
+ ? "A theme error occurred. This might be due to connection issues. Please refresh the page."
33
+ : "Something went wrong. Please refresh the page or try again later.";
34
+
24
35
  // Show a toast notification for the error
25
- toast.error(
26
- "Something went wrong. Please refresh the page or try again later.",
27
- {
28
- toastId: "error-boundary",
29
- icon: <ErrorIcon />,
30
- autoClose: 10000,
31
- }
32
- );
36
+ toast.error(errorMessage, {
37
+ toastId: "error-boundary",
38
+ icon: <ErrorIcon />,
39
+ autoClose: 10000,
40
+ });
33
41
 
34
42
  // Log error to external service if needed
35
43
  if (this.props.onError) {
@@ -57,11 +65,14 @@ class ErrorBoundary extends React.Component {
57
65
  border: "1px solid #dee2e6",
58
66
  borderRadius: "8px",
59
67
  margin: "20px",
68
+ minHeight: "200px",
69
+ display: "flex",
70
+ flexDirection: "column",
71
+ justifyContent: "center",
72
+ alignItems: "center",
60
73
  }}
61
74
  >
62
- <ErrorIcon
63
- style={{ fontSize: "48px", color: "#dc3545", marginBottom: "16px" }}
64
- />
75
+ <div style={{ fontSize: "48px", marginBottom: "16px" }}>⚠️</div>
65
76
  <h2 style={{ color: "#343a40", marginBottom: "16px" }}>
66
77
  Something went wrong
67
78
  </h2>
@@ -97,7 +108,9 @@ class ErrorBoundary extends React.Component {
97
108
  </button>
98
109
 
99
110
  {process.env.NODE_ENV === "development" && this.state.error && (
100
- <details style={{ marginTop: "20px", textAlign: "left" }}>
111
+ <details
112
+ style={{ marginTop: "20px", textAlign: "left", width: "100%" }}
113
+ >
101
114
  <summary style={{ cursor: "pointer", fontWeight: "bold" }}>
102
115
  Error Details (Development)
103
116
  </summary>
@@ -109,6 +122,8 @@ class ErrorBoundary extends React.Component {
109
122
  overflow: "auto",
110
123
  fontSize: "12px",
111
124
  marginTop: "10px",
125
+ maxHeight: "300px",
126
+ textAlign: "left",
112
127
  }}
113
128
  >
114
129
  {this.state.error && this.state.error.toString()}
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+ import { ThemeProvider, createTheme } from "@mui/material/styles";
3
+
4
+ // Fallback theme for when the main app theme is not available
5
+ const fallbackTheme = createTheme({
6
+ palette: {
7
+ mode: "light",
8
+ primary: {
9
+ main: "#1976d2",
10
+ },
11
+ secondary: {
12
+ main: "#dc3545",
13
+ },
14
+ error: {
15
+ main: "#d32f2f",
16
+ },
17
+ warning: {
18
+ main: "#ed6c02",
19
+ },
20
+ info: {
21
+ main: "#0288d1",
22
+ },
23
+ success: {
24
+ main: "#2e7d32",
25
+ },
26
+ },
27
+ });
28
+
29
+ const ThemeWrapper = ({ children, theme }) => {
30
+ // Use the provided theme or fallback theme
31
+ const safeTheme = theme || fallbackTheme;
32
+
33
+ return <ThemeProvider theme={safeTheme}>{children}</ThemeProvider>;
34
+ };
35
+
36
+ export default ThemeWrapper;
package/src/index.js CHANGED
@@ -2,6 +2,7 @@ import React, { createContext, useState, useEffect, useCallback } from "react";
2
2
  import versionCompare from "./components/versionCompare";
3
3
  import getDeviceFingerprint from "./components/FingerPrint";
4
4
  import ErrorBoundary from "./components/ErrorBoundary";
5
+ import ThemeWrapper from "./components/ThemeWrapper";
5
6
  // Notifications
6
7
  import { ToastContainer, toast } from "react-toastify";
7
8
  import "react-toastify/dist/ReactToastify.css";
@@ -90,6 +91,12 @@ const SessionManagerProvider = ({
90
91
  })
91
92
  .catch((err) => {
92
93
  console.error("Token refresh failed:", err);
94
+
95
+ // Track auth failures
96
+ if (err?.code === "ERR_NETWORK" || err?.code === "ERR_CONNECTION_REFUSED") {
97
+ setAuthError(true);
98
+ }
99
+
93
100
  // Clear invalid tokens
94
101
  localStorage.removeItem("Authorization");
95
102
  sessionStorage.removeItem("Authorization");
@@ -98,13 +105,19 @@ const SessionManagerProvider = ({
98
105
 
99
106
  // Only show toast for actual network/server errors, not auth failures
100
107
  if (err?.code === "ERR_NETWORK" || err?.response?.status >= 500) {
101
- toast.error(
102
- "Unable to refresh your session. Please login again.",
103
- {
104
- toastId: "token-refresh-error",
105
- icon: <Logout />,
106
- }
107
- );
108
+ // Don't spam with toasts during retries
109
+ const lastToast = sessionStorage.getItem("lastRefreshErrorToast");
110
+ const now = Date.now();
111
+ if (!lastToast || now - parseInt(lastToast) > 30000) { // 30 seconds
112
+ toast.error(
113
+ "Unable to refresh your session. Please login again.",
114
+ {
115
+ toastId: "token-refresh-error",
116
+ icon: <Logout />,
117
+ }
118
+ );
119
+ sessionStorage.setItem("lastRefreshErrorToast", now.toString());
120
+ }
108
121
  }
109
122
  });
110
123
  }, 100);
@@ -130,6 +143,7 @@ const SessionManagerProvider = ({
130
143
  const [isAdmin, setIsAdmin] = useState(false);
131
144
  const [userInfo, setUserInfo] = useState({});
132
145
  const [loadingUser, setLoadingUser] = useState(true);
146
+ const [authError, setAuthError] = useState(false);
133
147
 
134
148
  useEffect(() => {
135
149
  setTimeout(() => {
@@ -140,13 +154,18 @@ const SessionManagerProvider = ({
140
154
  setCurrentLoggedIn(data.logged_in);
141
155
  setIsAdmin(data.is_admin);
142
156
  setUserInfo(data.Info || {});
157
+ setAuthError(false);
143
158
  }
144
159
  })
145
160
  .catch((err) => {
146
161
  console.error("User data loading failed:", err);
147
- // Don't show toast for auth errors (401, 403)
148
- if (err?.response?.status !== 401 && err?.response?.status !== 403) {
149
- if (err?.code === "ERR_NETWORK" || err?.response?.status >= 500) {
162
+
163
+ // Check if this is a persistent auth error
164
+ if (err?.code === "ERR_NETWORK" || err?.code === "ERR_CONNECTION_REFUSED") {
165
+ setAuthError(true);
166
+ // Don't show toast immediately, let retries happen first
167
+ } else if (err?.response?.status !== 401 && err?.response?.status !== 403) {
168
+ if (err?.response?.status >= 500) {
150
169
  toast.error(
151
170
  "Unable to load user information. Some features may be limited.",
152
171
  {
@@ -193,6 +212,8 @@ const SessionManagerProvider = ({
193
212
  const customInterceptor = () => {
194
213
  AuthenticatedAxiosObject.interceptors.response.use(
195
214
  (response) => {
215
+ // Reset connection failure count on successful response
216
+ sessionStorage.setItem("connectionFailures", "0");
196
217
  return response;
197
218
  },
198
219
  (error) => {
@@ -262,10 +283,18 @@ const SessionManagerProvider = ({
262
283
  ? "Unable to connect to the server. Please check your internet connection and try again."
263
284
  : "The server is not responding, please reload or try again later.";
264
285
 
265
- toast.error(errorMessage, {
266
- toastId: `${error?.code || "ERR_CONNECTION_REFUSED"}`,
267
- icon: <GppBad />,
268
- });
286
+ // Only show toast after multiple failures to avoid spam
287
+ const failureCount = parseInt(sessionStorage.getItem("connectionFailures") || "0");
288
+ sessionStorage.setItem("connectionFailures", (failureCount + 1).toString());
289
+
290
+ if (failureCount >= 3) {
291
+ toast.error(errorMessage, {
292
+ toastId: `${error?.code || "ERR_CONNECTION_REFUSED"}`,
293
+ icon: <GppBad />,
294
+ });
295
+ // Reset counter after showing toast
296
+ sessionStorage.setItem("connectionFailures", "0");
297
+ }
269
298
  }
270
299
  return Promise.reject(error);
271
300
  }
@@ -353,25 +382,198 @@ const SessionManagerProvider = ({
353
382
  hasRole: hasRole,
354
383
  deviceUID: deviceUID,
355
384
  loadingUser: loadingUser,
385
+ authError: authError,
356
386
  };
357
387
 
388
+ // Show loading state while initializing
389
+ if (loadingUser) {
390
+ return (
391
+ <ThemeWrapper>
392
+ <ErrorBoundary>
393
+ <SessionManager.Provider value={contextValue}>
394
+ <div style={{
395
+ display: 'flex',
396
+ flexDirection: 'column',
397
+ alignItems: 'center',
398
+ justifyContent: 'center',
399
+ minHeight: '100vh',
400
+ padding: '20px',
401
+ backgroundColor: '#f5f5f5',
402
+ fontFamily: 'Arial, sans-serif'
403
+ }}>
404
+ <div style={{
405
+ backgroundColor: 'white',
406
+ padding: '40px',
407
+ borderRadius: '8px',
408
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
409
+ textAlign: 'center',
410
+ maxWidth: '400px'
411
+ }}>
412
+ <div style={{
413
+ width: '40px',
414
+ height: '40px',
415
+ border: '4px solid #f3f3f3',
416
+ borderTop: '4px solid #1976d2',
417
+ borderRadius: '50%',
418
+ animation: 'spin 1s linear infinite',
419
+ margin: '0 auto 16px'
420
+ }} />
421
+ <h3 style={{ color: '#333', marginBottom: '8px' }}>Loading...</h3>
422
+ <p style={{ color: '#666', margin: 0 }}>
423
+ Initializing session manager
424
+ </p>
425
+ </div>
426
+ <style>{`
427
+ @keyframes spin {
428
+ 0% { transform: rotate(0deg); }
429
+ 100% { transform: rotate(360deg); }
430
+ }
431
+ `}</style>
432
+ </div>
433
+ </SessionManager.Provider>
434
+ </ErrorBoundary>
435
+ </ThemeWrapper>
436
+ );
437
+ }
438
+ return (
439
+ <ThemeWrapper>
440
+ <ErrorBoundary>
441
+ <SessionManager.Provider value={contextValue}>
442
+ <ToastContainer
443
+ position="top-left"
444
+ autoClose={5000}
445
+ closeOnClick
446
+ pauseOnFocusLoss
447
+ pauseOnHover
448
+ newestOnTop={false}
449
+ toastClassName={"custToast materialToast"}
450
+ {...toastOptions}
451
+ />
452
+ <div style={{
453
+ display: 'flex',
454
+ flexDirection: 'column',
455
+ alignItems: 'center',
456
+ justifyContent: 'center',
457
+ minHeight: '100vh',
458
+ padding: '20px',
459
+ backgroundColor: '#f5f5f5',
460
+ fontFamily: 'Arial, sans-serif'
461
+ }}>
462
+ <div style={{
463
+ backgroundColor: 'white',
464
+ padding: '40px',
465
+ borderRadius: '8px',
466
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
467
+ textAlign: 'center',
468
+ maxWidth: '400px'
469
+ }}>
470
+ <div style={{ fontSize: '48px', marginBottom: '16px' }}>⚠️</div>
471
+ <h2 style={{ color: '#d32f2f', marginBottom: '16px' }}>Connection Error</h2>
472
+ <p style={{ color: '#666', marginBottom: '24px' }}>
473
+ Unable to connect to the server. Please check your internet connection and try again.
474
+ </p>
475
+ <button
476
+ onClick={() => window.location.reload()}
477
+ style={{
478
+ backgroundColor: '#1976d2',
479
+ color: 'white',
480
+ border: 'none',
481
+ padding: '12px 24px',
482
+ borderRadius: '4px',
483
+ cursor: 'pointer',
484
+ fontSize: '16px'
485
+ }}
486
+ >
487
+ Retry
488
+ </button>
489
+ </div>
490
+ </div>
491
+ </SessionManager.Provider>
492
+ </ErrorBoundary>
493
+ </ThemeWrapper>
494
+ );
495
+ }
496
+
497
+ // If there's a persistent auth error, render a minimal error state
498
+ if (authError && !loadingUser) {
499
+ return (
500
+ <ThemeWrapper>
501
+ <ErrorBoundary>
502
+ <SessionManager.Provider value={contextValue}>
503
+ <ToastContainer
504
+ position="top-left"
505
+ autoClose={5000}
506
+ closeOnClick
507
+ pauseOnFocusLoss
508
+ pauseOnHover
509
+ newestOnTop={false}
510
+ toastClassName={"custToast materialToast"}
511
+ {...toastOptions}
512
+ />
513
+ <div style={{
514
+ display: 'flex',
515
+ flexDirection: 'column',
516
+ alignItems: 'center',
517
+ justifyContent: 'center',
518
+ minHeight: '100vh',
519
+ padding: '20px',
520
+ backgroundColor: '#f5f5f5',
521
+ fontFamily: 'Arial, sans-serif'
522
+ }}>
523
+ <div style={{
524
+ backgroundColor: 'white',
525
+ padding: '40px',
526
+ borderRadius: '8px',
527
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
528
+ textAlign: 'center',
529
+ maxWidth: '400px'
530
+ }}>
531
+ <div style={{ fontSize: '48px', marginBottom: '16px' }}>⚠️</div>
532
+ <h2 style={{ color: '#d32f2f', marginBottom: '16px' }}>Connection Error</h2>
533
+ <p style={{ color: '#666', marginBottom: '24px' }}>
534
+ Unable to connect to the server. Please check your internet connection and try again.
535
+ </p>
536
+ <button
537
+ onClick={() => window.location.reload()}
538
+ style={{
539
+ backgroundColor: '#1976d2',
540
+ color: 'white',
541
+ border: 'none',
542
+ padding: '12px 24px',
543
+ borderRadius: '4px',
544
+ cursor: 'pointer',
545
+ fontSize: '16px'
546
+ }}
547
+ >
548
+ Retry
549
+ </button>
550
+ </div>
551
+ </div>
552
+ </SessionManager.Provider>
553
+ </ErrorBoundary>
554
+ </ThemeWrapper>
555
+ );
556
+ }
557
+
358
558
  return (
359
- <ErrorBoundary>
360
- <SessionManager.Provider value={contextValue}>
361
- <ToastContainer
362
- position="top-left"
363
- autoClose={5000}
364
- closeOnClick
365
- pauseOnFocusLoss
366
- pauseOnHover
367
- newestOnTop={false}
368
- toastClassName={"custToast materialToast"}
369
- {...toastOptions}
370
- />
371
- <VersionProtection appVersion={appVersion} />
372
- {children}
373
- </SessionManager.Provider>
374
- </ErrorBoundary>
559
+ <ThemeWrapper>
560
+ <ErrorBoundary>
561
+ <SessionManager.Provider value={contextValue}>
562
+ <ToastContainer
563
+ position="top-left"
564
+ autoClose={5000}
565
+ closeOnClick
566
+ pauseOnFocusLoss
567
+ pauseOnHover
568
+ newestOnTop={false}
569
+ toastClassName={"custToast materialToast"}
570
+ {...toastOptions}
571
+ />
572
+ <VersionProtection appVersion={appVersion} />
573
+ {children}
574
+ </SessionManager.Provider>
575
+ </ErrorBoundary>
576
+ </ThemeWrapper>
375
577
  );
376
578
  };
377
579