diff --git a/src/components/App.tsx b/src/components/App.tsx index 686ef68..e46c25b 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -14,10 +14,10 @@ const ION_AUTHORIZATION_ENDPOINT = dev : 'https://ion.tjhsst.edu/oauth/authorize?response_type=code&client_id=rNa6n9YSg8ftINdyVPpUsaMuxNbHLo9dh1OsOktR&scope=read&redirect_uri=https%3A%2F%2Fwheelshare.space%2Fauth%2Fion%2Fcallback'; export default function App() { - const { isLoggedIn, user } = useContext(AuthenticationContext); + const { user } = useContext(AuthenticationContext); return (
- {isLoggedIn ? ( + {user ? (
- {user!.name}{' '} + {user.name}{' '} Log out diff --git a/src/components/Authentication/AuthenticationContext.ts b/src/components/Authentication/AuthenticationContext.ts index 4e0f362..bac9ad6 100644 --- a/src/components/Authentication/AuthenticationContext.ts +++ b/src/components/Authentication/AuthenticationContext.ts @@ -6,20 +6,19 @@ export type User = { email?: string; }; -export type AuthState = { - isLoggedIn: boolean | null; +export type AuthenticationContextProps = { user: User | null; /** * Function that can be used to trigger an auth state refresh. */ - refreshAuthState: (() => void) | null; + refresh: () => void; }; -const AuthenticationContext = createContext({ - isLoggedIn: false, +const AuthenticationContext = createContext({ user: null, - refreshAuthState: null, + refresh: () => + console.warn('calling refresh on default AuthenticationContext'), }); export default AuthenticationContext; diff --git a/src/components/Authentication/AuthenticationWrapper.tsx b/src/components/Authentication/AuthenticationWrapper.tsx index d438d1f..f367800 100644 --- a/src/components/Authentication/AuthenticationWrapper.tsx +++ b/src/components/Authentication/AuthenticationWrapper.tsx @@ -1,45 +1,30 @@ import { useCallback, useEffect, useState } from 'react'; import { getMe } from '../api'; -import AuthenticationContext, { AuthState } from './AuthenticationContext'; +import AuthenticationContext, { User } from './AuthenticationContext'; export default function AuthenticationWrapper({ children, }: { children: React.ReactNode; }) { - const sessionToken = localStorage.getItem('session_token'); // Prevent race conditions - const [authState, setAuthState] = useState({ - isLoggedIn: null, - user: null, - refreshAuthState: null, - }); + const [user, setUser] = useState(null); - const refreshAuthState = useCallback(() => { - const loggedOut = () => - setAuthState({ isLoggedIn: false, user: null, refreshAuthState }); + const refresh = useCallback(() => { + const none = () => setUser(null); + const sessionToken = localStorage.getItem('session_token'); if (sessionToken) { - getMe() - .then((user) => { - if (user) { - setAuthState({ isLoggedIn: true, user, refreshAuthState }); - } else { - loggedOut(); - } - }) - .catch(loggedOut); + getMe().then(setUser).catch(none); } else { - loggedOut(); + none(); } - }, [sessionToken]); + }, []); - useEffect(() => { - refreshAuthState(); - }, [refreshAuthState]); + useEffect(refresh, [refresh]); return ( - + {children} ); diff --git a/src/components/Authentication/Authenticator.tsx b/src/components/Authentication/Authenticator.tsx index 83f9313..58ad628 100644 --- a/src/components/Authentication/Authenticator.tsx +++ b/src/components/Authentication/Authenticator.tsx @@ -3,45 +3,51 @@ import { Redirect, useLocation, useParams } from 'react-router-dom'; import AuthenticationContext from './AuthenticationContext'; import { createSession } from './createSession'; +function useCode() { + const location = useLocation(); + const query = new URLSearchParams(location.search); + const code = query.get('code'); + + return code; +} + export default function Authenticator() { const { provider } = useParams<{ provider: string }>(); - const query = new URLSearchParams(useLocation().search); - const code = query.get('code'); - const { refreshAuthState } = useContext(AuthenticationContext); - const [status, setStatus] = - useState<'pending' | 'errored' | 'authenticated'>('pending'); + const code = useCode(); + const { refresh } = useContext(AuthenticationContext); + + const [pending, setPending] = useState(true); const [token, setToken] = useState(null); useEffect(() => { + if (token) { + localStorage.setItem('session_token', token); + } else { + localStorage.removeItem('session_token'); + } + }, [token]); + + useEffect(() => { + setPending(true); createSession(code!) - .then((data) => { - if (data.status === 'success') { - console.log('Success! Token:', data.token); - setToken(data.token); - localStorage.setItem('session_token', data.token); - setStatus('authenticated'); - } else { - console.log('Authentication failure.'); - setToken(null); - localStorage.removeItem('session_token'); - setStatus('errored'); - } + .then(({ token }) => { + setToken(token ?? null); }) - .catch(() => { - setStatus('errored'); - }); + .finally(() => setPending(false)); }, [code, provider]); useEffect(() => { - refreshAuthState && refreshAuthState(); - }, [token, refreshAuthState]); + refresh(); + }, [token, refresh]); - switch (status) { - case 'authenticated': - return ; - case 'errored': - return

Sign In Error

; - case 'pending': - return

Signing In

; + if (pending) { + return

Signing In

; } + + if (token) { + return ; + } + + // If we aren't pending anymore, but don't have a token, we must have errored + return

Sign In Error

; }