varminer-app-header 2.2.3 → 2.2.4

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
@@ -421,13 +421,129 @@ function getAccessTokenFromAuth(auth) {
421
421
  auth.token;
422
422
  return typeof token === "string" && token.length > 0 ? token : undefined;
423
423
  }
424
- const fetchProfilePictureAsBlobUrl = async (baseUrl = "http://objectstore.impact0mics.local:9012") => {
424
+ /** True if string looks like a JWT (three base64 parts) or a bearer token, not JSON. */
425
+ function looksLikeToken(s) {
426
+ return s.length > 0 && !s.trimStart().startsWith("{") && !s.trimStart().startsWith("[");
427
+ }
428
+ /** Recursively find first string value at keys accessToken, access_token, or token. */
429
+ function findTokenInObject(obj) {
430
+ if (obj === null || obj === undefined)
431
+ return undefined;
432
+ if (typeof obj === "string")
433
+ return looksLikeToken(obj) ? obj : undefined;
434
+ if (typeof obj !== "object")
435
+ return undefined;
436
+ const rec = obj;
437
+ const direct = rec.accessToken ?? rec.access_token ?? rec.token;
438
+ if (typeof direct === "string" && looksLikeToken(direct))
439
+ return direct;
440
+ for (const key of Object.keys(rec)) {
441
+ const found = findTokenInObject(rec[key]);
442
+ if (found)
443
+ return found;
444
+ }
445
+ return undefined;
446
+ }
447
+ /** Parse redux-persist style value (may be double stringified). */
448
+ function parsePersistValue(raw) {
449
+ if (!raw)
450
+ return null;
451
+ try {
452
+ const first = JSON.parse(raw);
453
+ if (typeof first === "string") {
454
+ try {
455
+ return JSON.parse(first);
456
+ }
457
+ catch {
458
+ return first;
459
+ }
460
+ }
461
+ return first;
462
+ }
463
+ catch {
464
+ return null;
465
+ }
466
+ }
467
+ /** Get a nested value that may be a string (need parse) or already an object. */
468
+ function parseNestedValue(val) {
469
+ if (val == null)
470
+ return null;
471
+ if (typeof val === "string")
472
+ return parsePersistValue(val);
473
+ return val;
474
+ }
475
+ /**
476
+ * Extract access token from persist:userdb shape: authDetails (string) → parse → auth.accessToken.
477
+ * Structure: { authDetails: "{\"auth\":{\"accessToken\":\"...\"}}", profileInformation: "...", _persist: "..." }
478
+ */
479
+ function getTokenFromUserDbPersist(parsed) {
480
+ const authDetails = parsed.authDetails;
481
+ const inner = parseNestedValue(authDetails);
482
+ const obj = typeof inner === "object" && inner !== null ? inner : null;
483
+ if (!obj)
484
+ return undefined;
485
+ const auth = obj.auth;
486
+ const authObj = typeof auth === "object" && auth !== null ? auth : null;
487
+ if (!authObj)
488
+ return undefined;
489
+ const token = authObj.accessToken ??
490
+ authObj.access_token ??
491
+ authObj.token;
492
+ return typeof token === "string" && looksLikeToken(token) ? token : undefined;
493
+ }
494
+ /**
495
+ * Get access token from all known storage keys (header, IAM, userdb, and plain keys).
496
+ * persist:userdb shape: authDetails (stringified) contains auth.accessToken.
497
+ */
498
+ function getAccessTokenForRequest() {
499
+ const keysToTry = [
500
+ PERSIST_HEADER_KEY,
501
+ "persist:linn-i-am",
502
+ "persist:userdb",
503
+ "token",
504
+ "accessToken",
505
+ "auth",
506
+ ];
507
+ for (const key of keysToTry) {
508
+ const raw = localStorage.getItem(key);
509
+ if (!raw)
510
+ continue;
511
+ const parsed = key.startsWith("persist:") ? parsePersistValue(raw) : (() => { try {
512
+ return JSON.parse(raw);
513
+ }
514
+ catch {
515
+ return raw;
516
+ } })();
517
+ const token = findTokenInObject(parsed);
518
+ if (token)
519
+ return token;
520
+ if (key.startsWith("persist:")) {
521
+ const outer = typeof parsed === "object" && parsed !== null ? parsed : null;
522
+ if (outer) {
523
+ if (key === "persist:userdb") {
524
+ const fromUserDb = getTokenFromUserDbPersist(outer);
525
+ if (fromUserDb)
526
+ return fromUserDb;
527
+ }
528
+ for (const k of Object.keys(outer)) {
529
+ const inner = parseNestedValue(outer[k]);
530
+ const t = findTokenInObject(inner);
531
+ if (t)
532
+ return t;
533
+ }
534
+ }
535
+ }
536
+ }
537
+ return getAccessTokenFromAuth(getAllDataFromStorage().auth);
538
+ }
539
+ const fetchProfilePictureAsBlobUrl = async (baseUrl = "http://objectstore.impact0mics.local:9012", accessTokenOverride) => {
425
540
  try {
426
541
  const profilePictureUrl = getProfilePictureUrl(baseUrl);
427
542
  if (!profilePictureUrl)
428
543
  return null;
429
- const allData = getAllDataFromStorage();
430
- const accessToken = getAccessTokenFromAuth(allData.auth);
544
+ const accessToken = (typeof accessTokenOverride === "string" && accessTokenOverride.length > 0
545
+ ? accessTokenOverride
546
+ : null) ?? getAccessTokenForRequest();
431
547
  const headers = {};
432
548
  if (accessToken) {
433
549
  headers["Authorization"] = `Bearer ${accessToken}`;
@@ -563,7 +679,7 @@ const DEFAULT_ROUTES = {
563
679
  profile: "/user/profile",
564
680
  logout: "/user/login",
565
681
  };
566
- const AppHeader = ({ language: languageProp }) => {
682
+ const AppHeader = ({ language: languageProp, accessToken: accessTokenProp }) => {
567
683
  // Get initial language from props, URL, localStorage, or default to 'en'
568
684
  const getInitialLanguage = () => {
569
685
  // Priority 1: Props
@@ -660,12 +776,18 @@ const AppHeader = ({ language: languageProp }) => {
660
776
  userRole = userRole || profileData.role || profileData.userRole || "";
661
777
  }
662
778
  }
779
+ const avatarSrc = storedUser?.avatar ??
780
+ allData.auth?.avatar ??
781
+ allData.profile?.avatar;
782
+ const initialsVal = storedUser?.initials ??
783
+ allData.auth?.initials ??
784
+ allData.profile?.initials;
663
785
  return {
664
786
  name: userName || "",
665
787
  email: userEmail || "",
666
788
  role: userRole || "",
667
- avatar: storedUser?.avatar || allData.auth?.avatar || allData.profile?.avatar || undefined,
668
- initials: storedUser?.initials || allData.auth?.initials || allData.profile?.initials || undefined,
789
+ avatar: typeof avatarSrc === "string" ? avatarSrc : undefined,
790
+ initials: typeof initialsVal === "string" ? initialsVal : undefined,
669
791
  };
670
792
  });
671
793
  const [notificationCount, setNotificationCount] = React.useState(() => {
@@ -680,8 +802,8 @@ const AppHeader = ({ language: languageProp }) => {
680
802
  // Fetch profile picture from API when component mounts or user data changes
681
803
  React.useEffect(() => {
682
804
  const fetchProfilePicture = async () => {
683
- // Try to fetch profile picture from API
684
- const blobUrl = await fetchProfilePictureAsBlobUrl();
805
+ const token = accessTokenProp ?? getAccessTokenForRequest();
806
+ const blobUrl = await fetchProfilePictureAsBlobUrl(undefined, token ?? undefined);
685
807
  if (blobUrl) {
686
808
  // Clean up previous blob URL if it exists
687
809
  setProfilePictureBlobUrl((prevUrl) => {
@@ -702,7 +824,7 @@ const AppHeader = ({ language: languageProp }) => {
702
824
  return null;
703
825
  });
704
826
  };
705
- }, []); // Only run once on mount - fetch when component loads
827
+ }, [accessTokenProp]); // Refetch when accessToken prop changes (e.g. after login)
706
828
  React.useEffect(() => {
707
829
  const allData = getAllDataFromStorage();
708
830
  let userName = "";
@@ -1039,6 +1161,7 @@ exports.DrawerProvider = DrawerProvider;
1039
1161
  exports.PERSIST_HEADER_KEY = PERSIST_HEADER_KEY;
1040
1162
  exports.USER_DETAILS_STORAGE_KEY = USER_DETAILS_STORAGE_KEY;
1041
1163
  exports.fetchProfilePictureAsBlobUrl = fetchProfilePictureAsBlobUrl;
1164
+ exports.getAccessTokenForRequest = getAccessTokenForRequest;
1042
1165
  exports.getAllDataFromStorage = getAllDataFromStorage;
1043
1166
  exports.getI18nLocaleFromStorage = getI18nLocaleFromStorage;
1044
1167
  exports.getMessageCountFromStorage = getMessageCountFromStorage;