11'use client'
22
33import type { ComponentType , PropsWithChildren } from 'react'
4- import { useEffect } from 'react'
5- import { createContext , useContext , useState } from 'react'
4+ import { useEffect , createContext , useContext , useState } from 'react'
65import { LoadingAnimation } from '@helpwave/hightide'
7- import { LoginPage } from '@/components/pages/login'
86import { login , logout , onTokenExpiringCallback , removeUser , renewToken , restoreSession } from '@/api/auth/authService'
97import type { User } from 'oidc-client-ts'
10- import { getConfig } from '@/utils/config'
11-
12- const config = getConfig ( )
8+ import { usePathname } from 'next/navigation'
139
1410type AuthContextType = {
1511 identity : User ,
@@ -23,54 +19,64 @@ type AuthState = {
2319 isLoading : boolean ,
2420}
2521
26-
27- // TODO add option for unprotected routes
2822export const AuthProvider = ( { children } : PropsWithChildren ) => {
29- const [ { isLoading, identity } , setAuthState ] = useState < AuthState > ( { isLoading : true } )
23+ const [ authState , setAuthState ] = useState < AuthState > ( { isLoading : true } )
24+ const pathname = usePathname ( )
3025
3126 useEffect ( ( ) => {
32- restoreSession ( ) . then ( identity => {
33- if ( identity ) {
34- setAuthState ( {
35- identity,
36- isLoading : false ,
37- } )
38- onTokenExpiringCallback ( async ( ) => {
39- console . debug ( 'Token expiring, refreshing...' )
40- const identity = await renewToken ( )
41- setAuthState ( {
42- identity : identity ?? undefined ,
43- isLoading : false ,
44- } )
45- } )
46- } else {
47- login ( config . auth . redirect_uri + `?redirect_uri=${ encodeURIComponent ( window . location . href ) } ` ) . catch ( console . error )
27+ if ( pathname === '/auth/callback' ) {
28+ setAuthState ( { isLoading : false , identity : undefined } )
29+ return
30+ }
31+
32+ let isMounted = true
33+
34+ const initAuth = async ( ) => {
35+ try {
36+ const identity = await restoreSession ( )
37+
38+ if ( isMounted ) {
39+ if ( identity ) {
40+ setAuthState ( { identity, isLoading : false } )
41+
42+ onTokenExpiringCallback ( async ( ) => {
43+ const refreshedIdentity = await renewToken ( )
44+ setAuthState ( {
45+ identity : refreshedIdentity ?? undefined ,
46+ isLoading : false ,
47+ } )
48+ } )
49+ } else {
50+ await login ( )
51+ }
52+ }
53+ } catch {
54+ if ( isMounted ) {
55+ await removeUser ( )
56+ await login ( )
57+ }
4858 }
49- } ) . catch ( async ( ) => {
50- await removeUser ( )
51- await login ( config . auth . redirect_uri + `?redirect_uri=${ encodeURIComponent ( window . location . href ) } ` )
52- } )
53- } , [ ] )
59+ }
5460
55- if ( ! identity && isLoading ) {
56- return (
57- < div className = "flex-col-0 items-center justify-center w-screen h-screen" >
58- < LoadingAnimation loadingText = "Logging in..." />
59- </ div >
60- )
61+ initAuth ( )
62+
63+ return ( ) => { isMounted = false }
64+ } , [ pathname ] )
65+
66+ if ( pathname === '/auth/callback' ) {
67+ return < > { children } </ >
6168 }
6269
63- if ( ! identity ) {
70+ if ( authState . isLoading || ! authState . identity ) {
6471 return (
65- < LoginPage login = { async ( ) => {
66- await login ( config . auth . redirect_uri + `?redirect_uri=${ encodeURIComponent ( window . location . href ) } ` )
67- return true
68- } } />
72+ < div className = "flex flex-col items-center justify-center w-screen h-screen" >
73+ < LoadingAnimation loadingText = "Redirecting to login..." />
74+ </ div >
6975 )
7076 }
7177
7278 return (
73- < AuthContext . Provider value = { { identity, logout } } >
79+ < AuthContext . Provider value = { { identity : authState . identity , logout } } >
7480 { children }
7581 </ AuthContext . Provider >
7682 )
@@ -87,7 +93,6 @@ export const withAuth = <P extends object>(Component: ComponentType<P>) => {
8793 return WrappedComponent
8894}
8995
90-
9196export const useAuth = ( ) => {
9297 const context = useContext ( AuthContext )
9398 if ( ! context ) {
0 commit comments