Created
May 14, 2020 17:03
-
-
Save Jnforja/da40d5c773c8e2b3da60f3445442770e to your computer and use it in GitHub Desktop.
Example of context and hook for authentication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useContext, useEffect, useState, useRef } from 'react'; | |
import { login } from './login-service'; | |
import { fetchUser as fetchUserRequest } from './fetch-user'; | |
import { removeAccessToken } from './access-token-storage'; | |
import styles from './auth-context.module.scss'; | |
const AuthContext = React.createContext(); | |
function AuthProvider({ | |
fetchUser = fetchUserRequest, | |
children, | |
performLogin = login, | |
performLogout = removeAccessToken, | |
}) { | |
const [isLoading, setIsLoading] = useState(true); | |
const [user, setUser] = useState(); | |
const [hasError, setHasError] = useState(false); | |
const doFetchUserRequest = useRef(async () => { | |
setIsLoading(true); | |
await fetchUser().then(handleFetchUserResponse); | |
setIsLoading(false); | |
function handleFetchUserResponse(data) { | |
const { user, errorCode } = data; | |
user ? setUser(user) : setUser(null); | |
errorCode === 'request_failure' && setHasError(true); | |
} | |
}).current; | |
async function loginWithFetchUser(credentials) { | |
const res = await performLogin(credentials); | |
if (res.success) { | |
await doFetchUserRequest(); | |
} | |
return res; | |
} | |
function logout() { | |
performLogout(); | |
setUser(null); | |
} | |
useEffect(() => { | |
doFetchUserRequest(); | |
}, [doFetchUserRequest]); | |
if (hasError) { | |
return <ErrorScreen />; | |
} | |
if (isLoading) { | |
return <LoadingScreen />; | |
} | |
return ( | |
<AuthContext.Provider value={{ user, login: loginWithFetchUser, logout }} children={children} /> | |
); | |
} | |
function LoadingScreen() { | |
return ( | |
<div className={styles['wrap']}> | |
<div className={styles['lds-ring']}> | |
<div></div> | |
<div></div> | |
<div></div> | |
<div></div> | |
<p className={styles['lds-ring__label']}>Loading...</p> | |
</div> | |
</div> | |
); | |
} | |
function ErrorScreen() { | |
const circleWithCrossIcon = ( | |
<svg viewBox='0 0 24 24' fill='none'> | |
<path | |
d='M10 14L12 12M12 12L14 10M12 12L10 10M12 12L14 14M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z' | |
stroke='var(--red-600)' | |
strokeWidth='2' | |
strokeLinecap='round' | |
strokeLinejoin='round' | |
/> | |
</svg> | |
); | |
return ( | |
<div className={styles['screen']}> | |
<div className={styles['error-modal']}> | |
<div className={styles['with-sidebar']}> | |
<div> | |
<div className={styles['sidebar']}> | |
<div className={styles['error-modal__icon']}>{circleWithCrossIcon}</div> | |
</div> | |
<div className={`${styles['not-sidebar']} ${styles['error-modal__content']}`}> | |
<h1 className={styles['error-modal__content__title']}>There was an error...</h1> | |
<p className={styles['error-modal__content__text']}> | |
An unexpected error has occurred. Please try again later. If the error persists, | |
please contact our support team. | |
</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
); | |
} | |
function useAuth() { | |
const context = useContext(AuthContext); | |
if (context === undefined) { | |
throw new Error(`useAuth must be used within a AuthProvider`); | |
} | |
return context; | |
} | |
export { AuthProvider, useAuth }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment