authscape 1.0.712 → 1.0.714
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/index.js +90 -33
- package/package.json +1 -1
- package/src/components/AuthScapeApp.js +92 -42
package/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
4
3
|
Object.defineProperty(exports, "__esModule", {
|
|
5
4
|
value: true
|
|
6
5
|
});
|
|
@@ -30,6 +29,50 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
|
|
|
30
29
|
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
31
30
|
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
32
31
|
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
32
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
33
|
+
// ---- optional: import your cookie util if not global ----
|
|
34
|
+
// import { setCookie } from "cookies-next";
|
|
35
|
+
// import { apiService } from "@/services/api"; // wherever yours lives
|
|
36
|
+
|
|
37
|
+
// Decorate a user object with role/permission helpers (idempotent)
|
|
38
|
+
function ensureUserHelpers(u) {
|
|
39
|
+
if (!u || _typeof(u) !== "object") return u;
|
|
40
|
+
|
|
41
|
+
// Avoid redefining on every call
|
|
42
|
+
if (typeof u.hasRole === "function" && typeof u.hasRoleId === "function" && typeof u.hasPermission === "function") {
|
|
43
|
+
return u;
|
|
44
|
+
}
|
|
45
|
+
var rolesArr = Array.isArray(u.roles) ? u.roles : [];
|
|
46
|
+
var permsArr = Array.isArray(u.permissions) ? u.permissions : [];
|
|
47
|
+
|
|
48
|
+
// defineProperty keeps them non-enumerable
|
|
49
|
+
Object.defineProperty(u, "hasRole", {
|
|
50
|
+
value: function hasRole(name) {
|
|
51
|
+
if (!name) return false;
|
|
52
|
+
return rolesArr.some(function (r) {
|
|
53
|
+
return (r === null || r === void 0 ? void 0 : r.name) === name;
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
writable: false
|
|
57
|
+
});
|
|
58
|
+
Object.defineProperty(u, "hasRoleId", {
|
|
59
|
+
value: function hasRoleId(id) {
|
|
60
|
+
if (id === undefined || id === null) return false;
|
|
61
|
+
return rolesArr.some(function (r) {
|
|
62
|
+
return (r === null || r === void 0 ? void 0 : r.id) === id;
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
writable: false
|
|
66
|
+
});
|
|
67
|
+
Object.defineProperty(u, "hasPermission", {
|
|
68
|
+
value: function hasPermission(name) {
|
|
69
|
+
if (!name) return false;
|
|
70
|
+
return permsArr.includes(name);
|
|
71
|
+
},
|
|
72
|
+
writable: false
|
|
73
|
+
});
|
|
74
|
+
return u;
|
|
75
|
+
}
|
|
33
76
|
function AuthScapeApp(_ref) {
|
|
34
77
|
var Component = _ref.Component,
|
|
35
78
|
layout = _ref.layout,
|
|
@@ -63,20 +106,20 @@ function AuthScapeApp(_ref) {
|
|
|
63
106
|
var queryCode = searchParams.get("code");
|
|
64
107
|
var pathname = (0, _navigation.usePathname)();
|
|
65
108
|
|
|
66
|
-
//
|
|
109
|
+
// ----- PKCE Sign-in (browser-only) -----
|
|
67
110
|
var signInValidator = /*#__PURE__*/function () {
|
|
68
|
-
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(
|
|
69
|
-
var codeVerifier, headers,
|
|
111
|
+
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(codeFromQuery) {
|
|
112
|
+
var codeVerifier, headers, body, response, domainHost, redirectUri;
|
|
70
113
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
71
114
|
while (1) switch (_context.prev = _context.next) {
|
|
72
115
|
case 0:
|
|
73
|
-
if (!(queryCodeUsed.current ===
|
|
116
|
+
if (!(queryCodeUsed.current === codeFromQuery)) {
|
|
74
117
|
_context.next = 2;
|
|
75
118
|
break;
|
|
76
119
|
}
|
|
77
120
|
return _context.abrupt("return");
|
|
78
121
|
case 2:
|
|
79
|
-
queryCodeUsed.current =
|
|
122
|
+
queryCodeUsed.current = codeFromQuery;
|
|
80
123
|
if (!(typeof window === "undefined")) {
|
|
81
124
|
_context.next = 5;
|
|
82
125
|
break;
|
|
@@ -84,7 +127,7 @@ function AuthScapeApp(_ref) {
|
|
|
84
127
|
return _context.abrupt("return");
|
|
85
128
|
case 5:
|
|
86
129
|
codeVerifier = window.localStorage.getItem("verifier");
|
|
87
|
-
if (!(!
|
|
130
|
+
if (!(!codeFromQuery || !codeVerifier)) {
|
|
88
131
|
_context.next = 8;
|
|
89
132
|
break;
|
|
90
133
|
}
|
|
@@ -93,8 +136,8 @@ function AuthScapeApp(_ref) {
|
|
|
93
136
|
headers = {
|
|
94
137
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
95
138
|
};
|
|
96
|
-
|
|
97
|
-
code:
|
|
139
|
+
body = _queryString["default"].stringify({
|
|
140
|
+
code: codeFromQuery,
|
|
98
141
|
grant_type: "authorization_code",
|
|
99
142
|
redirect_uri: window.location.origin + "/signin-oidc",
|
|
100
143
|
client_id: process.env.client_id,
|
|
@@ -103,13 +146,15 @@ function AuthScapeApp(_ref) {
|
|
|
103
146
|
});
|
|
104
147
|
_context.prev = 10;
|
|
105
148
|
_context.next = 13;
|
|
106
|
-
return _axios["default"].post(process.env.authorityUri + "/connect/token",
|
|
149
|
+
return _axios["default"].post(process.env.authorityUri + "/connect/token", body, {
|
|
107
150
|
headers: headers
|
|
108
151
|
});
|
|
109
152
|
case 13:
|
|
110
153
|
response = _context.sent;
|
|
111
154
|
domainHost = window.location.hostname.split(".").slice(-2).join(".");
|
|
112
155
|
window.localStorage.removeItem("verifier");
|
|
156
|
+
|
|
157
|
+
// NOTE: replace setCookie below with your implementation if different
|
|
113
158
|
_context.next = 18;
|
|
114
159
|
return setCookie("access_token", response.data.access_token, {
|
|
115
160
|
maxAge: 60 * 60 * 24 * 365,
|
|
@@ -134,8 +179,8 @@ function AuthScapeApp(_ref) {
|
|
|
134
179
|
secure: true
|
|
135
180
|
});
|
|
136
181
|
case 22:
|
|
137
|
-
redirectUri = localStorage.getItem("redirectUri");
|
|
138
|
-
localStorage.clear();
|
|
182
|
+
redirectUri = window.localStorage.getItem("redirectUri");
|
|
183
|
+
window.localStorage.clear();
|
|
139
184
|
window.location.href = redirectUri || "/";
|
|
140
185
|
_context.next = 30;
|
|
141
186
|
break;
|
|
@@ -154,7 +199,7 @@ function AuthScapeApp(_ref) {
|
|
|
154
199
|
};
|
|
155
200
|
}();
|
|
156
201
|
|
|
157
|
-
//
|
|
202
|
+
// ----- GA + Clarity -----
|
|
158
203
|
function initGA(_x2) {
|
|
159
204
|
return _initGA.apply(this, arguments);
|
|
160
205
|
}
|
|
@@ -189,9 +234,8 @@ function AuthScapeApp(_ref) {
|
|
|
189
234
|
return _initGA.apply(this, arguments);
|
|
190
235
|
}
|
|
191
236
|
var logEvent = function logEvent(category, action, label) {
|
|
192
|
-
if (ga4React.current)
|
|
193
|
-
|
|
194
|
-
}
|
|
237
|
+
if (ga4React.current) ga4React.current.event(action, label, category);
|
|
238
|
+
// your DB analytics can go here if desired
|
|
195
239
|
};
|
|
196
240
|
var databaseDrivenPageView = function databaseDrivenPageView(pathName) {
|
|
197
241
|
var _signedInUser$current, _signedInUser$current2, _signedInUser$current3;
|
|
@@ -208,16 +252,23 @@ function AuthScapeApp(_ref) {
|
|
|
208
252
|
});
|
|
209
253
|
};
|
|
210
254
|
|
|
211
|
-
//
|
|
255
|
+
// ----- Auth init (runs once) -----
|
|
212
256
|
(0, _react.useEffect)(function () {
|
|
213
257
|
if (queryCode) {
|
|
214
258
|
signInValidator(queryCode);
|
|
215
|
-
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (!loadingAuth.current) {
|
|
216
262
|
loadingAuth.current = true;
|
|
217
263
|
if (enableAuth) {
|
|
218
264
|
apiService().GetCurrentUser().then(function (usr) {
|
|
219
|
-
signedInUser.current = usr;
|
|
220
|
-
setSignedInUserState(
|
|
265
|
+
signedInUser.current = ensureUserHelpers(usr);
|
|
266
|
+
setSignedInUserState(signedInUser.current);
|
|
267
|
+
setFrontEndLoadedState(true);
|
|
268
|
+
})["catch"](function () {
|
|
269
|
+
// no user / anonymous
|
|
270
|
+
signedInUser.current = null;
|
|
271
|
+
setSignedInUserState(null);
|
|
221
272
|
setFrontEndLoadedState(true);
|
|
222
273
|
});
|
|
223
274
|
} else {
|
|
@@ -226,7 +277,7 @@ function AuthScapeApp(_ref) {
|
|
|
226
277
|
}
|
|
227
278
|
}, [queryCode, enableAuth]);
|
|
228
279
|
|
|
229
|
-
//
|
|
280
|
+
// ----- Analytics init -----
|
|
230
281
|
(0, _react.useEffect)(function () {
|
|
231
282
|
if (!frontEndLoadedState || typeof window === "undefined") return;
|
|
232
283
|
if (pageProps.googleAnalytics4Code) {
|
|
@@ -240,44 +291,50 @@ function AuthScapeApp(_ref) {
|
|
|
240
291
|
_reactMicrosoftClarity.clarity.init(process.env.microsoftClarityTrackingCode);
|
|
241
292
|
}
|
|
242
293
|
databaseDrivenPageView(window.location.pathname);
|
|
243
|
-
|
|
294
|
+
var handler = function handler(url) {
|
|
244
295
|
var _ga4React$current;
|
|
245
296
|
(_ga4React$current = ga4React.current) === null || _ga4React$current === void 0 || _ga4React$current.pageview(url);
|
|
246
297
|
databaseDrivenPageView(url);
|
|
247
|
-
}
|
|
248
|
-
|
|
298
|
+
};
|
|
299
|
+
_router["default"].events.on("routeChangeComplete", handler);
|
|
300
|
+
return function () {
|
|
301
|
+
return _router["default"].events.off("routeChangeComplete", handler);
|
|
302
|
+
};
|
|
303
|
+
}, [frontEndLoadedState, pageProps.googleAnalytics4Code, pageProps.microsoftClarityCode]);
|
|
249
304
|
|
|
250
|
-
//
|
|
305
|
+
// ----- Enforce login (client) -----
|
|
251
306
|
(0, _react.useEffect)(function () {
|
|
252
307
|
if (enforceLoggedIn && pathname !== "/signin-oidc" && frontEndLoadedState && !signedInUserState) {
|
|
253
308
|
(0, _authscape.authService)().login();
|
|
254
309
|
}
|
|
255
310
|
}, [signedInUserState, enforceLoggedIn, frontEndLoadedState, pathname]);
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
311
|
+
|
|
312
|
+
// Stable getter for current user (with helpers)
|
|
313
|
+
var currentUser = (0, _react.useMemo)(function () {
|
|
314
|
+
return ensureUserHelpers(signedInUser.current);
|
|
315
|
+
}, [signedInUserState]);
|
|
316
|
+
var useStore = (0, _zustand.create)(function () {
|
|
260
317
|
return store;
|
|
261
318
|
});
|
|
262
319
|
|
|
263
|
-
//
|
|
320
|
+
// ----- Render (SSR-safe; always output page so <title> is visible) -----
|
|
264
321
|
var pageContent = layout ? layout({
|
|
265
322
|
children: /*#__PURE__*/_react["default"].createElement(Component, _extends({}, pageProps, {
|
|
266
|
-
currentUser:
|
|
323
|
+
currentUser: currentUser,
|
|
267
324
|
loadedUser: frontEndLoadedState,
|
|
268
325
|
setIsLoading: setIsLoadingShow,
|
|
269
326
|
logEvent: logEvent,
|
|
270
327
|
store: useStore,
|
|
271
328
|
toast: _reactToastify.toast
|
|
272
329
|
})),
|
|
273
|
-
currentUser:
|
|
330
|
+
currentUser: currentUser,
|
|
274
331
|
setIsLoading: setIsLoadingShow,
|
|
275
332
|
logEvent: logEvent,
|
|
276
333
|
toast: _reactToastify.toast,
|
|
277
334
|
store: useStore,
|
|
278
335
|
pageProps: pageProps
|
|
279
336
|
}) : /*#__PURE__*/_react["default"].createElement(Component, _extends({}, pageProps, {
|
|
280
|
-
currentUser:
|
|
337
|
+
currentUser: currentUser,
|
|
281
338
|
loadedUser: frontEndLoadedState,
|
|
282
339
|
setIsLoading: setIsLoadingShow,
|
|
283
340
|
logEvent: logEvent,
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useRef, useEffect } from "react";
|
|
1
|
+
import React, { useState, useRef, useEffect, useMemo } from "react";
|
|
2
2
|
import { ToastContainer, toast } from "react-toastify";
|
|
3
3
|
import { ThemeProvider } from "@mui/material/styles";
|
|
4
4
|
import Head from "next/head";
|
|
@@ -11,6 +11,52 @@ import { create } from "zustand";
|
|
|
11
11
|
import { clarity } from "react-microsoft-clarity";
|
|
12
12
|
import { authService } from "authscape";
|
|
13
13
|
|
|
14
|
+
// ---- optional: import your cookie util if not global ----
|
|
15
|
+
// import { setCookie } from "cookies-next";
|
|
16
|
+
// import { apiService } from "@/services/api"; // wherever yours lives
|
|
17
|
+
|
|
18
|
+
// Decorate a user object with role/permission helpers (idempotent)
|
|
19
|
+
function ensureUserHelpers(u) {
|
|
20
|
+
if (!u || typeof u !== "object") return u;
|
|
21
|
+
|
|
22
|
+
// Avoid redefining on every call
|
|
23
|
+
if (typeof u.hasRole === "function" &&
|
|
24
|
+
typeof u.hasRoleId === "function" &&
|
|
25
|
+
typeof u.hasPermission === "function") {
|
|
26
|
+
return u;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const rolesArr = Array.isArray(u.roles) ? u.roles : [];
|
|
30
|
+
const permsArr = Array.isArray(u.permissions) ? u.permissions : [];
|
|
31
|
+
|
|
32
|
+
// defineProperty keeps them non-enumerable
|
|
33
|
+
Object.defineProperty(u, "hasRole", {
|
|
34
|
+
value: function hasRole(name) {
|
|
35
|
+
if (!name) return false;
|
|
36
|
+
return rolesArr.some(r => r?.name === name);
|
|
37
|
+
},
|
|
38
|
+
writable: false
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
Object.defineProperty(u, "hasRoleId", {
|
|
42
|
+
value: function hasRoleId(id) {
|
|
43
|
+
if (id === undefined || id === null) return false;
|
|
44
|
+
return rolesArr.some(r => r?.id === id);
|
|
45
|
+
},
|
|
46
|
+
writable: false
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
Object.defineProperty(u, "hasPermission", {
|
|
50
|
+
value: function hasPermission(name) {
|
|
51
|
+
if (!name) return false;
|
|
52
|
+
return permsArr.includes(name);
|
|
53
|
+
},
|
|
54
|
+
writable: false
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return u;
|
|
58
|
+
}
|
|
59
|
+
|
|
14
60
|
export function AuthScapeApp({
|
|
15
61
|
Component,
|
|
16
62
|
layout,
|
|
@@ -34,20 +80,20 @@ export function AuthScapeApp({
|
|
|
34
80
|
const queryCode = searchParams.get("code");
|
|
35
81
|
const pathname = usePathname();
|
|
36
82
|
|
|
37
|
-
//
|
|
38
|
-
const signInValidator = async (
|
|
39
|
-
if (queryCodeUsed.current ===
|
|
40
|
-
queryCodeUsed.current =
|
|
83
|
+
// ----- PKCE Sign-in (browser-only) -----
|
|
84
|
+
const signInValidator = async (codeFromQuery) => {
|
|
85
|
+
if (queryCodeUsed.current === codeFromQuery) return;
|
|
86
|
+
queryCodeUsed.current = codeFromQuery;
|
|
41
87
|
|
|
42
88
|
if (typeof window === "undefined") return;
|
|
43
89
|
|
|
44
90
|
const codeVerifier = window.localStorage.getItem("verifier");
|
|
45
|
-
if (!
|
|
91
|
+
if (!codeFromQuery || !codeVerifier) return;
|
|
46
92
|
|
|
47
93
|
const headers = { "Content-Type": "application/x-www-form-urlencoded" };
|
|
48
94
|
|
|
49
|
-
const
|
|
50
|
-
code:
|
|
95
|
+
const body = querystring.stringify({
|
|
96
|
+
code: codeFromQuery,
|
|
51
97
|
grant_type: "authorization_code",
|
|
52
98
|
redirect_uri: window.location.origin + "/signin-oidc",
|
|
53
99
|
client_id: process.env.client_id,
|
|
@@ -58,17 +104,15 @@ export function AuthScapeApp({
|
|
|
58
104
|
try {
|
|
59
105
|
const response = await axios.post(
|
|
60
106
|
process.env.authorityUri + "/connect/token",
|
|
61
|
-
|
|
107
|
+
body,
|
|
62
108
|
{ headers }
|
|
63
109
|
);
|
|
64
110
|
|
|
65
|
-
const domainHost = window.location.hostname
|
|
66
|
-
.split(".")
|
|
67
|
-
.slice(-2)
|
|
68
|
-
.join(".");
|
|
111
|
+
const domainHost = window.location.hostname.split(".").slice(-2).join(".");
|
|
69
112
|
|
|
70
113
|
window.localStorage.removeItem("verifier");
|
|
71
114
|
|
|
115
|
+
// NOTE: replace setCookie below with your implementation if different
|
|
72
116
|
await setCookie("access_token", response.data.access_token, {
|
|
73
117
|
maxAge: 60 * 60 * 24 * 365,
|
|
74
118
|
path: "/",
|
|
@@ -88,24 +132,18 @@ export function AuthScapeApp({
|
|
|
88
132
|
secure: true,
|
|
89
133
|
});
|
|
90
134
|
|
|
91
|
-
const redirectUri = localStorage.getItem("redirectUri");
|
|
92
|
-
localStorage.clear();
|
|
135
|
+
const redirectUri = window.localStorage.getItem("redirectUri");
|
|
136
|
+
window.localStorage.clear();
|
|
93
137
|
window.location.href = redirectUri || "/";
|
|
94
138
|
} catch (exp) {
|
|
95
139
|
console.error("PKCE sign-in failed", exp);
|
|
96
140
|
}
|
|
97
141
|
};
|
|
98
142
|
|
|
99
|
-
//
|
|
143
|
+
// ----- GA + Clarity -----
|
|
100
144
|
async function initGA(G) {
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
!GA4React.isInitialized() &&
|
|
104
|
-
G
|
|
105
|
-
) {
|
|
106
|
-
ga4React.current = new GA4React(G, {
|
|
107
|
-
debug_mode: !process.env.production,
|
|
108
|
-
});
|
|
145
|
+
if (typeof window !== "undefined" && !GA4React.isInitialized() && G) {
|
|
146
|
+
ga4React.current = new GA4React(G, { debug_mode: !process.env.production });
|
|
109
147
|
try {
|
|
110
148
|
await ga4React.current.initialize();
|
|
111
149
|
} catch (error) {
|
|
@@ -115,9 +153,8 @@ export function AuthScapeApp({
|
|
|
115
153
|
}
|
|
116
154
|
|
|
117
155
|
const logEvent = (category, action, label) => {
|
|
118
|
-
if (ga4React.current)
|
|
119
|
-
|
|
120
|
-
}
|
|
156
|
+
if (ga4React.current) ga4React.current.event(action, label, category);
|
|
157
|
+
// your DB analytics can go here if desired
|
|
121
158
|
};
|
|
122
159
|
|
|
123
160
|
const databaseDrivenPageView = (pathName) => {
|
|
@@ -136,16 +173,25 @@ export function AuthScapeApp({
|
|
|
136
173
|
});
|
|
137
174
|
};
|
|
138
175
|
|
|
139
|
-
//
|
|
176
|
+
// ----- Auth init (runs once) -----
|
|
140
177
|
useEffect(() => {
|
|
141
178
|
if (queryCode) {
|
|
142
179
|
signInValidator(queryCode);
|
|
143
|
-
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (!loadingAuth.current) {
|
|
144
184
|
loadingAuth.current = true;
|
|
185
|
+
|
|
145
186
|
if (enableAuth) {
|
|
146
187
|
apiService().GetCurrentUser().then((usr) => {
|
|
147
|
-
signedInUser.current = usr;
|
|
148
|
-
setSignedInUserState(
|
|
188
|
+
signedInUser.current = ensureUserHelpers(usr);
|
|
189
|
+
setSignedInUserState(signedInUser.current);
|
|
190
|
+
setFrontEndLoadedState(true);
|
|
191
|
+
}).catch(() => {
|
|
192
|
+
// no user / anonymous
|
|
193
|
+
signedInUser.current = null;
|
|
194
|
+
setSignedInUserState(null);
|
|
149
195
|
setFrontEndLoadedState(true);
|
|
150
196
|
});
|
|
151
197
|
} else {
|
|
@@ -154,7 +200,7 @@ export function AuthScapeApp({
|
|
|
154
200
|
}
|
|
155
201
|
}, [queryCode, enableAuth]);
|
|
156
202
|
|
|
157
|
-
//
|
|
203
|
+
// ----- Analytics init -----
|
|
158
204
|
useEffect(() => {
|
|
159
205
|
if (!frontEndLoadedState || typeof window === "undefined") return;
|
|
160
206
|
|
|
@@ -172,13 +218,15 @@ export function AuthScapeApp({
|
|
|
172
218
|
|
|
173
219
|
databaseDrivenPageView(window.location.pathname);
|
|
174
220
|
|
|
175
|
-
|
|
221
|
+
const handler = (url) => {
|
|
176
222
|
ga4React.current?.pageview(url);
|
|
177
223
|
databaseDrivenPageView(url);
|
|
178
|
-
}
|
|
179
|
-
|
|
224
|
+
};
|
|
225
|
+
Router.events.on("routeChangeComplete", handler);
|
|
226
|
+
return () => Router.events.off("routeChangeComplete", handler);
|
|
227
|
+
}, [frontEndLoadedState, pageProps.googleAnalytics4Code, pageProps.microsoftClarityCode]);
|
|
180
228
|
|
|
181
|
-
//
|
|
229
|
+
// ----- Enforce login (client) -----
|
|
182
230
|
useEffect(() => {
|
|
183
231
|
if (
|
|
184
232
|
enforceLoggedIn &&
|
|
@@ -190,16 +238,18 @@ export function AuthScapeApp({
|
|
|
190
238
|
}
|
|
191
239
|
}, [signedInUserState, enforceLoggedIn, frontEndLoadedState, pathname]);
|
|
192
240
|
|
|
193
|
-
|
|
194
|
-
const
|
|
241
|
+
// Stable getter for current user (with helpers)
|
|
242
|
+
const currentUser = useMemo(() => ensureUserHelpers(signedInUser.current), [signedInUserState]);
|
|
243
|
+
|
|
244
|
+
const useStore = create(() => store);
|
|
195
245
|
|
|
196
|
-
//
|
|
246
|
+
// ----- Render (SSR-safe; always output page so <title> is visible) -----
|
|
197
247
|
const pageContent = layout
|
|
198
248
|
? layout({
|
|
199
249
|
children: (
|
|
200
250
|
<Component
|
|
201
251
|
{...pageProps}
|
|
202
|
-
currentUser={
|
|
252
|
+
currentUser={currentUser}
|
|
203
253
|
loadedUser={frontEndLoadedState}
|
|
204
254
|
setIsLoading={setIsLoadingShow}
|
|
205
255
|
logEvent={logEvent}
|
|
@@ -207,7 +257,7 @@ export function AuthScapeApp({
|
|
|
207
257
|
toast={toast}
|
|
208
258
|
/>
|
|
209
259
|
),
|
|
210
|
-
currentUser
|
|
260
|
+
currentUser,
|
|
211
261
|
setIsLoading: setIsLoadingShow,
|
|
212
262
|
logEvent,
|
|
213
263
|
toast,
|
|
@@ -217,7 +267,7 @@ export function AuthScapeApp({
|
|
|
217
267
|
: (
|
|
218
268
|
<Component
|
|
219
269
|
{...pageProps}
|
|
220
|
-
currentUser={
|
|
270
|
+
currentUser={currentUser}
|
|
221
271
|
loadedUser={frontEndLoadedState}
|
|
222
272
|
setIsLoading={setIsLoadingShow}
|
|
223
273
|
logEvent={logEvent}
|