import { createContext, useContext, useEffect, useReducer, useRef } from 'react'; import PropTypes from 'prop-types'; const HANDLERS = { INITIALIZE: 'INITIALIZE', SIGN_IN: 'SIGN_IN', SIGN_OUT: 'SIGN_OUT' }; const initialState = { isAuthenticated: false, isLoading: true, user: null }; const handlers = { [HANDLERS.INITIALIZE]: (state, action) => { const user = action.payload; return { ...state, ...( // if payload (user) is provided, then is authenticated user ? ({ isAuthenticated: true, isLoading: false, user }) : ({ isLoading: false }) ) }; }, [HANDLERS.SIGN_IN]: (state, action) => { const user = action.payload; return { ...state, isAuthenticated: true, user }; }, [HANDLERS.SIGN_OUT]: (state) => { return { ...state, isAuthenticated: false, user: null }; } }; const reducer = (state, action) => ( handlers[action.type] ? handlers[action.type](state, action) : state ); // The role of this context is to propagate authentication state through the App tree. export const AuthContext = createContext({ undefined }); export const AuthProvider = (props) => { const { children } = props; const [state, dispatch] = useReducer(reducer, initialState); const initialized = useRef(false); const initialize = async () => { // Prevent from calling twice in development mode with React.StrictMode enabled if (initialized.current) { return; } initialized.current = true; let isAuthenticated = false; try { isAuthenticated = window.sessionStorage.getItem('authenticated') === 'true'; } catch (err) { console.error(err); } if (isAuthenticated) { const user = { id: '5e86809283e28b96d2d38537', avatar: '/assets/avatars/default-avatar.png', name: 'Anika Visser', email: 'anika.visser@devias.io', }; dispatch({ type: HANDLERS.INITIALIZE, payload: user }); } else { dispatch({ type: HANDLERS.INITIALIZE }); } }; useEffect( () => { initialize(); }, // eslint-disable-next-line react-hooks/exhaustive-deps [] ); const skip = () => { try { window.sessionStorage.setItem('authenticated', 'true'); } catch (err) { console.error(err); } const user = { id: '5e86809283e28b96d2d38537', avatar: '/assets/avatars/default-avatar.png', name: 'Anika Visser', email: 'anika.visser@devias.io', }; dispatch({ type: HANDLERS.SIGN_IN, payload: user }); }; const signIn = async (email, password) => { var myHeaders = new Headers(); myHeaders.append("Content-Type", "application/json"); var raw = JSON.stringify({ "email": email, "password": password }); var requestOptions = { method: 'PUT', headers: myHeaders, body: raw, redirect: 'follow' }; let result = await fetch(process.env.NEXT_PUBLIC_REST_ENPOINT+"/auth/login", requestOptions) if (result.status != 200) { throw new Error('Please check your email and password'); } const token = await result.json() try { window.sessionStorage.setItem('authenticated', 'true'); } catch (err) { console.error(err); } const user = { id: '5e86809283e28b96d2d38537', avatar: '/assets/avatars/default-avatar.png', name: 'Anika Visser', email: 'anika.visser@devias.io', token: token }; localStorage.setItem("token", token) dispatch({ type: HANDLERS.SIGN_IN, payload: user }); }; const signUp = async (email, name, password) => { throw new Error('Sign up is not implemented'); }; const signOut = () => { dispatch({ type: HANDLERS.SIGN_OUT }); }; return ( {children} ); }; AuthProvider.propTypes = { children: PropTypes.node }; export const AuthConsumer = AuthContext.Consumer; export const useAuthContext = () => useContext(AuthContext);