varminer-app-header 2.6.3 → 2.6.5

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/dist/index.js CHANGED
@@ -128,21 +128,80 @@ function setHeaderAuth(auth) {
128
128
  }
129
129
  }
130
130
  /**
131
- * User display data: from IAM only (linn-i-am-userDetails). No dependency on persist:userdb.
131
+ * User display data: prefers linn-i-am-userDetails (IAM), falls back to
132
+ * persist:userdb → profileInformation.userDetails, then authDetails.auth.user.
132
133
  */
133
134
  const getUserDataFromStorage = () => {
135
+ // Primary source: IAM app sets this after OTP verification
134
136
  const iamUser = getStoredUserDetails();
135
- if (!iamUser)
136
- return null;
137
- const name = [iamUser.firstName, iamUser.lastName].filter(Boolean).join(" ").trim();
138
- const role = iamUser.roles?.length ? iamUser.roles[0] : iamUser.workInfo?.jobTitle ?? "";
139
- return {
140
- name: name || "",
141
- email: iamUser.email || "",
142
- role: role || "",
143
- avatar: undefined,
144
- initials: name ? name.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase() : undefined,
145
- };
137
+ if (iamUser) {
138
+ const name = [iamUser.firstName, iamUser.lastName].filter(Boolean).join(" ").trim();
139
+ const role = iamUser.roles?.length ? iamUser.roles[0] : iamUser.workInfo?.jobTitle ?? "";
140
+ return {
141
+ name: name || "",
142
+ email: iamUser.email || "",
143
+ role: role || "",
144
+ avatar: undefined,
145
+ initials: name ? name.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase() : undefined,
146
+ };
147
+ }
148
+ // Fallback: read from persist:userdb which is written by the IAM/login app
149
+ try {
150
+ const raw = localStorage.getItem("persist:userdb");
151
+ if (!raw)
152
+ return null;
153
+ const outer = JSON.parse(raw);
154
+ const parseNested = (v) => {
155
+ if (typeof v === "string") {
156
+ try {
157
+ return JSON.parse(v);
158
+ }
159
+ catch {
160
+ return v;
161
+ }
162
+ }
163
+ return v;
164
+ };
165
+ // profileInformation.userDetails has firstName, lastName, email, roles[]
166
+ const profileInfo = parseNested(outer.profileInformation);
167
+ const userDetails = profileInfo?.userDetails;
168
+ if (userDetails && (userDetails.firstName || userDetails.lastName || userDetails.email)) {
169
+ const first = userDetails.firstName || "";
170
+ const last = userDetails.lastName || "";
171
+ const name = [first, last].filter(Boolean).join(" ").trim();
172
+ const roles = userDetails.roles;
173
+ const role = roles?.length ? roles[0] : userDetails.jobTitle ?? "";
174
+ return {
175
+ name,
176
+ email: userDetails.email || "",
177
+ role: role || "",
178
+ avatar: undefined,
179
+ initials: name ? name.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase() : undefined,
180
+ };
181
+ }
182
+ // authDetails.auth.user has firstname/lastname (lowercase n) or firstName/lastName (camelCase) + activeRole
183
+ const authDetailsRaw = parseNested(outer.authDetails);
184
+ const auth = authDetailsRaw?.auth;
185
+ const userObj = auth?.user;
186
+ const firstFromUser = (userObj?.firstname ?? userObj?.firstName ?? userObj?.given_name ?? userObj?.first_name) || "";
187
+ const lastFromUser = (userObj?.lastname ?? userObj?.lastName ?? userObj?.family_name ?? userObj?.last_name) || "";
188
+ const emailFromUser = (userObj?.email ?? userObj?.emailAddress) || (auth?.email ?? auth?.sub) || "";
189
+ if (auth && (firstFromUser || lastFromUser || emailFromUser)) {
190
+ const name = [firstFromUser, lastFromUser].filter(Boolean).join(" ").trim();
191
+ const role = auth.activeRole || auth.role || "";
192
+ return {
193
+ name,
194
+ email: emailFromUser,
195
+ role,
196
+ avatar: undefined,
197
+ initials: name ? name.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase() : undefined,
198
+ };
199
+ }
200
+ }
201
+ catch {
202
+ // ignore parse errors
203
+ }
204
+ return null;
146
205
  };
147
206
  const getNotificationCountFromStorage = () => {
148
207
  const userDbString = localStorage.getItem("persist:userdb");
@@ -297,49 +356,7 @@ const getAllDataFromStorage = () => {
297
356
  console.error("Error parsing header persist:", err);
298
357
  }
299
358
  }
300
- // Fallback: try IAM persist key (persist:linn-i-am) then persist:userdb
301
- const tryParsePersistForAuth = (raw) => {
302
- if (!raw)
303
- return null;
304
- try {
305
- const outer = JSON.parse(raw);
306
- const parseNested = (v) => typeof v === "string" ? (() => { try {
307
- return JSON.parse(v);
308
- }
309
- catch {
310
- return v;
311
- } })() : v;
312
- for (const key of Object.keys(outer)) {
313
- const parsed = parseNested(outer[key]);
314
- if (parsed?.accessToken || parsed?.access_token || parsed?.token || parsed?.refreshToken)
315
- return parsed;
316
- if (parsed?.auth && typeof parsed.auth === "object") {
317
- const a = parsed.auth;
318
- if (a.accessToken || a.access_token || a.token)
319
- return a;
320
- }
321
- }
322
- }
323
- catch {
324
- /* ignore */
325
- }
326
- return null;
327
- };
328
- const iamPersist = localStorage.getItem("persist:linn-i-am");
329
- const iamAuth = tryParsePersistForAuth(iamPersist);
330
- if (iamAuth) {
331
- const token = (iamAuth.accessToken ?? iamAuth.access_token ?? iamAuth.token);
332
- if (token) {
333
- const decodedToken = decodeJWT(token);
334
- return {
335
- ...emptyStorageResult(),
336
- auth: iamAuth,
337
- decodedToken: decodedToken ? Object.fromEntries(Object.entries(decodedToken).map(([k, v]) => [k, v ?? null])) : null,
338
- rawData: iamAuth,
339
- };
340
- }
341
- }
342
- // Fallback: read access token from persist:userdb (e.g. legacy or shared auth)
359
+ // Fallback: read access token from persist:userdb
343
360
  const userDbString = localStorage.getItem("persist:userdb");
344
361
  if (!userDbString) {
345
362
  return emptyStorageResult();
@@ -540,7 +557,6 @@ function getTokenFromUserDbPersist(parsed) {
540
557
  function getAccessTokenForRequest() {
541
558
  const keysToTry = [
542
559
  PERSIST_HEADER_KEY,
543
- "persist:linn-i-am",
544
560
  "persist:userdb",
545
561
  "token",
546
562
  "accessToken",
@@ -806,6 +822,35 @@ const AppHeader = ({ language: languageProp, accessToken: accessTokenProp, objec
806
822
  let userName = "";
807
823
  let userEmail = "";
808
824
  let userRole = "";
825
+ // === DEBUG ===
826
+ const _allLSKeys = [];
827
+ for (let i = 0; i < localStorage.length; i++) {
828
+ const k = localStorage.key(i);
829
+ if (k)
830
+ _allLSKeys.push(k);
831
+ }
832
+ const _dbgRaw = {};
833
+ _allLSKeys.forEach(k => {
834
+ const v = localStorage.getItem(k);
835
+ if (v) {
836
+ try {
837
+ _dbgRaw[k] = JSON.parse(v);
838
+ }
839
+ catch {
840
+ _dbgRaw[k] = v;
841
+ }
842
+ }
843
+ else {
844
+ _dbgRaw[k] = null;
845
+ }
846
+ });
847
+ console.warn("▶▶▶ [AppHeader DEBUG] ALL localStorage keys:", _allLSKeys);
848
+ console.warn("▶▶▶ [AppHeader DEBUG] ALL localStorage values:", _dbgRaw);
849
+ console.warn("▶▶▶ [AppHeader DEBUG] linn-i-am-userDetails:", localStorage.getItem("linn-i-am-userDetails"));
850
+ console.warn("▶▶▶ [AppHeader DEBUG] persist:userdb (raw):", localStorage.getItem("persist:userdb"));
851
+ console.warn("▶▶▶ [AppHeader DEBUG] getAllDataFromStorage():", allData);
852
+ console.warn("▶▶▶ [AppHeader DEBUG] getUserDataFromStorage():", getUserDataFromStorage());
853
+ // === END DEBUG ===
809
854
  const buildNameFromFirstLast = (obj) => {
810
855
  if (!obj || typeof obj !== "object")
811
856
  return "";
@@ -830,8 +875,9 @@ const AppHeader = ({ language: languageProp, accessToken: accessTokenProp, objec
830
875
  }
831
876
  if (allData.auth) {
832
877
  const auth = allData.auth;
833
- userEmail = userEmail || auth.email || auth.sub || "";
834
- userName = userName || auth.name || buildNameFromFirstLast(auth) || "";
878
+ const authUser = auth.user;
879
+ userEmail = userEmail || auth.email || auth.sub || authUser?.email || authUser?.emailAddress || "";
880
+ userName = userName || auth.name || buildNameFromFirstLast(auth) || buildNameFromFirstLast(authUser) || "";
835
881
  userRole = userRole || auth.role || auth.activeRole || "";
836
882
  }
837
883
  if (allData.userDetails) {
@@ -874,13 +920,15 @@ const AppHeader = ({ language: languageProp, accessToken: accessTokenProp, objec
874
920
  const initialsVal = storedUser?.initials ??
875
921
  allData.auth?.initials ??
876
922
  allData.profile?.initials;
877
- return {
923
+ const resolvedUser = {
878
924
  name: userName || "",
879
925
  email: userEmail || "",
880
926
  role: userRole || "",
881
927
  avatar: typeof avatarSrc === "string" ? avatarSrc : undefined,
882
928
  initials: typeof initialsVal === "string" ? initialsVal : undefined,
883
929
  };
930
+ console.warn("▶▶▶ [AppHeader DEBUG] Resolved user state (name/email/role):", resolvedUser);
931
+ return resolvedUser;
884
932
  });
885
933
  const [notificationCount, setNotificationCount] = React.useState(() => {
886
934
  const count = getNotificationCountFromStorage();
@@ -948,8 +996,9 @@ const AppHeader = ({ language: languageProp, accessToken: accessTokenProp, objec
948
996
  }
949
997
  if (allData.auth) {
950
998
  const auth = allData.auth;
951
- userEmail = userEmail || auth.email || auth.sub || "";
952
- userName = userName || auth.name || buildNameFromFirstLast(auth) || "";
999
+ const authUser = auth.user;
1000
+ userEmail = userEmail || auth.email || auth.sub || authUser?.email || authUser?.emailAddress || "";
1001
+ userName = userName || auth.name || buildNameFromFirstLast(auth) || buildNameFromFirstLast(authUser) || "";
953
1002
  userRole = userRole || auth.role || auth.activeRole || "";
954
1003
  userAvatar = userAvatar || auth.avatar || undefined;
955
1004
  userInitials = userInitials || auth.initials || undefined;
@@ -1160,7 +1209,7 @@ const AppHeader = ({ language: languageProp, accessToken: accessTokenProp, objec
1160
1209
  width: "100%",
1161
1210
  maxWidth: 360,
1162
1211
  pointerEvents: "none",
1163
- }, component: "div", "aria-hidden": "true", tabIndex: -1, children: jsxRuntime.jsxs(material.ListItem, { alignItems: "flex-start", className: "profile-menu-item", children: [jsxRuntime.jsx(material.ListItemAvatar, { children: isOnlineStatus ? (jsxRuntime.jsx(OnlineBadge, { overlap: "circular", anchorOrigin: { vertical: "bottom", horizontal: "right" }, variant: "dot", title: t.online, "aria-label": `${t.online} status badge`, "data-testid": "online-badge", children: jsxRuntime.jsx(material.Avatar, { sx: { bgcolor: colors.deepOrange[500] }, alt: user.name, title: user.name, src: user.avatar, children: getInitials() }) })) : (jsxRuntime.jsx(OfflineBadge, { overlap: "circular", anchorOrigin: { vertical: "bottom", horizontal: "right" }, variant: "dot", title: t.offline, "aria-label": `${t.offline} status badge`, "data-testid": "offline-badge", children: jsxRuntime.jsx(material.Avatar, { sx: { bgcolor: colors.deepOrange[500] }, alt: user.name, title: user.name, src: user.avatar, children: getInitials() }) })) }), jsxRuntime.jsx(material.ListItemText, { primary: jsxRuntime.jsx(material.Typography, { className: "profile-name", component: "span", children: user.name || user.email }), secondary: jsxRuntime.jsxs(React.Fragment, { children: [user.name && user.email ? (jsxRuntime.jsx(material.Typography, { className: "profile-email", component: "p", children: user.email })) : null, jsxRuntime.jsxs(material.Typography, { className: "profile-role", component: "p", children: [t.role, ": ", user.role] })] }) })] }) }));
1212
+ }, component: "div", "aria-hidden": "true", tabIndex: -1, children: jsxRuntime.jsxs(material.ListItem, { alignItems: "flex-start", className: "profile-menu-item", children: [jsxRuntime.jsx(material.ListItemAvatar, { children: isOnlineStatus ? (jsxRuntime.jsx(OnlineBadge, { overlap: "circular", anchorOrigin: { vertical: "bottom", horizontal: "right" }, variant: "dot", title: t.online, "aria-label": `${t.online} status badge`, "data-testid": "online-badge", children: jsxRuntime.jsx(material.Avatar, { sx: { bgcolor: colors.deepOrange[500] }, alt: user.name, title: user.name, src: user.avatar, children: getInitials() }) })) : (jsxRuntime.jsx(OfflineBadge, { overlap: "circular", anchorOrigin: { vertical: "bottom", horizontal: "right" }, variant: "dot", title: t.offline, "aria-label": `${t.offline} status badge`, "data-testid": "offline-badge", children: jsxRuntime.jsx(material.Avatar, { sx: { bgcolor: colors.deepOrange[500] }, alt: user.name, title: user.name, src: user.avatar, children: getInitials() }) })) }), jsxRuntime.jsx(material.ListItemText, { primaryTypographyProps: { component: "span" }, secondaryTypographyProps: { component: "span" }, primary: jsxRuntime.jsx(material.Typography, { className: "profile-name", component: "span", children: user.name || user.email }), secondary: jsxRuntime.jsxs(React.Fragment, { children: [user.name && user.email ? (jsxRuntime.jsx(material.Typography, { className: "profile-email", component: "span", display: "block", children: user.email })) : null, jsxRuntime.jsxs(material.Typography, { className: "profile-role", component: "span", display: "block", children: [t.role, ": ", user.role] })] }) })] }) }));
1164
1213
  const renderMenu = (jsxRuntime.jsxs(material.Menu, { anchorEl: anchorEl, id: "account-menu", open: open, onClose: handleClose, onClick: handleClose, slotProps: {
1165
1214
  paper: {
1166
1215
  elevation: 0,