import { createContext, ReactNode, useEffect, useReducer } from 'react'; // utils import axios from '../utils/axios'; // import { isValidToken, setSession } from '../utils/jwt'; import { setSession, getSession, getUser } from '../utils/token'; // @types import { ActionMap, AuthState, AuthUser, JWTContextType } from '../@types/auth'; // ---------------------------------------------------------------------- import { Navigate, useLocation } from 'react-router-dom'; enum Types { Initial = 'INITIALIZE', Login = 'LOGIN', Logout = 'LOGOUT', Register = 'REGISTER', } type JWTAuthPayload = { [Types.Initial]: { isAuthenticated: boolean; user: AuthUser; }; [Types.Login]: { user: AuthUser; }; [Types.Logout]: undefined; [Types.Register]: { user: AuthUser; }; }; export type JWTActions = ActionMap[keyof ActionMap]; const initialState: AuthState = { isAuthenticated: false, isInitialized: false, user: null, }; const JWTReducer = (state: AuthState, action: JWTActions) => { switch (action.type) { case 'INITIALIZE': return { isAuthenticated: action.payload.isAuthenticated, isInitialized: true, user: action.payload.user, }; case 'LOGIN': return { ...state, isAuthenticated: true, user: action.payload.user, }; case 'LOGOUT': return { ...state, isAuthenticated: false, user: null, }; case 'REGISTER': return { ...state, isAuthenticated: true, user: action.payload.user, }; default: return state; } }; const AuthContext = createContext(null); // ---------------------------------------------------------------------- type AuthProviderProps = { children: ReactNode; }; function AuthProvider({ children }: AuthProviderProps) { const [state, dispatch] = useReducer(JWTReducer, initialState); let location = useLocation(); const accessToken = getSession(); useEffect(() => { (async () => { try { // const accessToken = getSession(); if (accessToken) { setSession(accessToken); const response = await axios.get('/user'); const user = response.data; dispatch({ type: Types.Initial, payload: { isAuthenticated: true, user, }, }); } else { dispatch({ type: Types.Initial, payload: { isAuthenticated: false, user: null, }, }); } } catch (err) { dispatch({ type: Types.Initial, payload: { isAuthenticated: false, user: null, }, }); } })(); }, [accessToken]); const login = async (email: string, password: string) => axios .post('/login', { email, password }) .then((response) => { const { user, token } = response.data; setSession(token); dispatch({ type: Types.Login, payload: { user, } }); }) .catch(error => { if (error.response.status !== 404) throw error.response if (error.response.status !== 422) throw error.response }); const register = async (email: string, password: string, firstName: string, lastName: string) => { const response = await axios.post('/api/register', { email, password, firstName, lastName, }); const { accessToken, user } = response.data; window.localStorage.setItem('accessToken', accessToken); dispatch({ type: Types.Register, payload: { user, }, }); }; const logout = async () => { setSession(null); dispatch({ type: Types.Logout }); }; return ( {children} ); // if (state.isInitialized) { // return (!state.isAuthenticated && location.pathname !== '/auth/login') ? // () // : false && location.pathname == '/auth/login' ? // () // : ( // // {children} // // ); // } else { // return () // } } export { AuthContext, AuthProvider };