diff --git a/src/components/header/header.test.tsx b/src/components/header/header.test.tsx index f6d956e6..ef7ada9f 100644 --- a/src/components/header/header.test.tsx +++ b/src/components/header/header.test.tsx @@ -35,6 +35,7 @@ describe('Header', () => { test('should navigate away from home', async () => { jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: true, + isLoading: false, currentUserData: {} as User, error: null, signIn: jest.fn(), @@ -50,6 +51,7 @@ describe('Header', () => { test('should handle sign in', async () => { jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: false, + isLoading: false, currentUserData: {} as User, error: null, signIn: jest.fn(), @@ -66,6 +68,7 @@ describe('Header', () => { test('should handle sign out', async () => { jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: true, + isLoading: false, currentUserData: {} as User, error: null, signIn: jest.fn(), diff --git a/src/components/protected-route/protected-route.test.tsx b/src/components/protected-route/protected-route.test.tsx index bf62dc89..a87a6db1 100644 --- a/src/components/protected-route/protected-route.test.tsx +++ b/src/components/protected-route/protected-route.test.tsx @@ -27,6 +27,7 @@ describe('ProtectedRoute', () => { test('should render successfully when signed in', async () => { jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: true, + isLoading: false, currentUserData: {} as User, error: null, signIn: jest.fn(), @@ -38,4 +39,21 @@ describe('ProtectedRoute', () => { expect(baseElement).toBeTruthy(); }); }); + + test('should render loading when not signed in and loading', async () => { + jest.spyOn(useAuthMock, 'default').mockReturnValue({ + isSignedIn: false, + isLoading: true, + currentUserData: {} as User, + error: null, + signIn: jest.fn(), + signOut: jest.fn(), + }); + + const { baseElement, getByText } = render(wrapperComponent); + await act(async () => { + expect(baseElement).toBeTruthy(); + expect(getByText('Loading...')).toBeTruthy(); + }); + }); }); diff --git a/src/components/protected-route/protected-route.tsx b/src/components/protected-route/protected-route.tsx index b2b61020..84bc511a 100644 --- a/src/components/protected-route/protected-route.tsx +++ b/src/components/protected-route/protected-route.tsx @@ -2,6 +2,13 @@ import useAuth from '@src/hooks/use-auth'; import { Navigate, Outlet } from 'react-router-dom'; export const ProtectedRoute = (): React.ReactElement => { - const { isSignedIn } = useAuth(); + const { isSignedIn, isLoading } = useAuth(); + if (isLoading) + return ( +
+
Loading...
+
+ ); + return isSignedIn ? : ; }; diff --git a/src/hooks/use-auth.ts b/src/hooks/use-auth.ts index caed2f41..ce903d42 100644 --- a/src/hooks/use-auth.ts +++ b/src/hooks/use-auth.ts @@ -9,6 +9,7 @@ import { User } from '../types/user'; const useAuth = () => { const auth = useKeycloakAuth(); const [isSignedIn, setIsSignedIn] = useRecoilState(signedIn); + const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(); const [currentUserData, setCurrentUserDate] = useRecoilState< User | undefined @@ -29,6 +30,10 @@ const useAuth = () => { } }, [auth.isAuthenticated, setIsSignedIn]); + useEffect(() => { + setIsLoading(auth.isLoading); + }, [auth.isLoading, setIsSignedIn]); + useEffect(() => { const profile = auth.user?.profile; if (profile) { @@ -72,7 +77,7 @@ const useAuth = () => { } }; - return { isSignedIn, currentUserData, error, signIn, signOut }; + return { isSignedIn, isLoading, currentUserData, error, signIn, signOut }; }; export default useAuth; diff --git a/src/pages/dashboard/dashboard.test.tsx b/src/pages/dashboard/dashboard.test.tsx index 97f7b409..682f2f4c 100644 --- a/src/pages/dashboard/dashboard.test.tsx +++ b/src/pages/dashboard/dashboard.test.tsx @@ -42,6 +42,7 @@ describe('Dashboard', () => { mock.onGet(new RegExp('/spacecraft')).reply(200, mockData); jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: true, + isLoading: false, currentUserData: {} as User, error: null, signIn: jest.fn(), diff --git a/src/pages/details/details.test.tsx b/src/pages/details/details.test.tsx index b154b690..2ae75073 100644 --- a/src/pages/details/details.test.tsx +++ b/src/pages/details/details.test.tsx @@ -47,6 +47,7 @@ describe('Details', () => { mock.onGet(new RegExp('/spacecraft/*')).reply(200, mockData.items[0]); jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: true, + isLoading: false, currentUserData: {} as User, error: null, signIn: jest.fn(), diff --git a/src/pages/home/home.test.tsx b/src/pages/home/home.test.tsx index 89f8a6db..e667675d 100644 --- a/src/pages/home/home.test.tsx +++ b/src/pages/home/home.test.tsx @@ -30,6 +30,7 @@ describe('Home', () => { test('should render with mock data', async () => { jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: true, + isLoading: false, currentUserData: { firstName: 'John', lastName: 'Doe' } as User, error: null, signIn: jest.fn(), diff --git a/src/pages/sign-in/sign-in.test.tsx b/src/pages/sign-in/sign-in.test.tsx index 375918a1..a5020178 100644 --- a/src/pages/sign-in/sign-in.test.tsx +++ b/src/pages/sign-in/sign-in.test.tsx @@ -63,6 +63,7 @@ describe('SignIn', () => { test('should simulate a successful login attempt', async () => { jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: false, + isLoading: false, currentUserData: {} as User, error: null, signIn: jest.fn(), @@ -82,6 +83,7 @@ describe('SignIn', () => { test('should simulate a successful login attempt when signed in', async () => { jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: true, + isLoading: false, currentUserData: {} as User, error: null, signIn: jest.fn(), @@ -101,6 +103,7 @@ describe('SignIn', () => { test('should simulate an unsuccessful login attempt', async () => { jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: false, + isLoading: false, currentUserData: {} as User, error: 'Error', signIn: jest.fn(), @@ -128,6 +131,7 @@ describe('SignIn', () => { test('should simulate an sso login', async () => { jest.spyOn(useAuthMock, 'default').mockReturnValue({ isSignedIn: false, + isLoading: false, currentUserData: {} as User, error: null, signIn: jest.fn(), diff --git a/src/utils/auth.test.ts b/src/utils/auth.test.ts index 41354c59..d58828b1 100644 --- a/src/utils/auth.test.ts +++ b/src/utils/auth.test.ts @@ -53,7 +53,7 @@ describe('Auth Helpers', () => { }); const url = getSignInRedirectUrl(); - expect(url).toEqual('http://localhost/signin'); + expect(url).toEqual('http://localhost/dashboard'); }); test('should verify no SSL config', () => { diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 94909da1..18c742ab 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -13,7 +13,7 @@ export const getDisplayName = (user: User): string => { }; export const getSignInRedirectUrl = (): string => { - return `${window.location.origin}/signin`; + return `${window.location.origin}/dashboard`; }; export const hasSsoConfig = (): boolean => { diff --git a/src/utils/keycloak.ts b/src/utils/keycloak.ts index 227e5bf7..cf551c87 100644 --- a/src/utils/keycloak.ts +++ b/src/utils/keycloak.ts @@ -1,9 +1,11 @@ +import { WebStorageStateStore } from 'oidc-client-ts'; import { getSignInRedirectUrl } from './auth'; const keycloak = { authority: process.env.SSO_AUTHORITY ? process.env.SSO_AUTHORITY : '', client_id: process.env.SSO_CLIENT_ID ? process.env.SSO_CLIENT_ID : '', redirect_uri: getSignInRedirectUrl(), + userStore: new WebStorageStateStore({ store: window.localStorage }), }; export default keycloak;