Skip to content

Instantly share code, notes, and snippets.

@Jnforja
Created May 14, 2020 17:03
Show Gist options
  • Save Jnforja/da40d5c773c8e2b3da60f3445442770e to your computer and use it in GitHub Desktop.
Save Jnforja/da40d5c773c8e2b3da60f3445442770e to your computer and use it in GitHub Desktop.
Example of context and hook for authentication
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