import { createContext, useContext, useEffect, useReducer, useRef } from 'react'; import PropTypes from 'prop-types'; import { useRouter } from 'next/router'; 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 router = useRouter(); 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); } console.log("isAuthenticated: ", isAuthenticated) if (isAuthenticated) { const user = { id: '5e86809283e28b96d2d38537', avatar: '/assets/avatars/default-avatar.png', name: 'Oktopus', email: 'anika.visser@devias.io', token: localStorage.getItem("token") }; dispatch({ type: HANDLERS.INITIALIZE, payload: user }); console.log("AUTH CONTEXT --> auth.user.token:", user.token) } 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: 'Oktopus', 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_ENDPOINT+"/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'); window.sessionStorage.setItem('email',email) } catch (err) { console.error(err); } const user = { id: '5e86809283e28b96d2d38537', avatar: '/assets/avatars/default-avatar.png', name: 'Oktopus', email: email, token: token }; localStorage.setItem("token", token) dispatch({ type: HANDLERS.SIGN_IN, payload: user }); }; const signUp = async (email, name, password) => { var myHeaders = new Headers(); myHeaders.append("Content-Type", "application/json"); var raw = JSON.stringify({ "email": email, "password": password, "name": name }); var requestOptions = { method: 'POST', headers: myHeaders, body: raw, redirect: 'follow' }; let result = await fetch(process.env.NEXT_PUBLIC_REST_ENDPOINT+"/auth/admin/register", requestOptions) if (result.status == 200) { router.push("/auth/login") }else{ const content = await result.json() throw new Error(content); } }; const signOut = () => { dispatch({ type: HANDLERS.SIGN_OUT }); }; return ( {children} ); }; AuthProvider.propTypes = { children: PropTypes.node }; export const AuthConsumer = AuthContext.Consumer; export const useAuthContext = () => useContext(AuthContext);