import { OidcClient, type OidcUserInfo } from '@axa-fr/oidc-client'; import { useEffect, useRef, useState } from 'react'; export enum OidcUserStatus { Unauthenticated = 'Unauthenticated', Loading = 'Loading user', Loaded = 'User loaded', LoadingError = 'Error loading user', } export type OidcUser = { user: T | null; status: OidcUserStatus; }; export const useOidcUser = ( configurationName = 'default', demonstrating_proof_of_possession = false, ) => { const oidc = OidcClient.get(configurationName); const user = oidc.userInfo(); const [oidcUser, setOidcUser] = useState>({ user: user, status: user ? OidcUserStatus.Loaded : OidcUserStatus.Unauthenticated, }); const [oidcUserId, setOidcUserId] = useState(user ? 1 : 0); const oidcPreviousUserIdRef = useRef(user ? 1 : 0); useEffect(() => { const oidc = OidcClient.get(configurationName); let isMounted = true; if (oidc && oidc.tokens) { const isCache = oidcUserId === oidcPreviousUserIdRef.current; if (isCache && oidc.userInfo()) { return; } oidcPreviousUserIdRef.current = oidcUserId; // Use queueMicrotask to defer setState to avoid synchronous call in effect queueMicrotask(() => { if (isMounted) { setOidcUser({ ...oidcUser, status: OidcUserStatus.Loading }); } }); oidc .userInfoAsync(!isCache, demonstrating_proof_of_possession) .then(info => { if (isMounted) { // @ts-ignore setOidcUser({ user: info, status: OidcUserStatus.Loaded }); } }) .catch(() => setOidcUser({ ...oidcUser, status: OidcUserStatus.LoadingError })); } else { queueMicrotask(() => { if (isMounted) { setOidcUser({ user: null, status: OidcUserStatus.Unauthenticated }); } }); } const newSubscriptionId = oidc.subscribeEvents((name: string) => { if ( name === OidcClient.eventNames.logout_from_another_tab || name === OidcClient.eventNames.logout_from_same_tab ) { if (isMounted) { setOidcUser({ user: null, status: OidcUserStatus.Unauthenticated }); } } }); return () => { isMounted = false; oidc.removeEventSubscription(newSubscriptionId); }; }, [oidcUserId, configurationName, demonstrating_proof_of_possession]); const reloadOidcUser = () => { setOidcUserId(oidcUserId + 1); }; return { oidcUser: oidcUser.user, oidcUserLoadingState: oidcUser.status, reloadOidcUser }; };