Untitled
unknown
plain_text
a year ago
4.6 kB
3
Indexable
'use client'; import { useEffect, useReducer, useCallback, useMemo } from 'react'; // utils import axios, { endpoints } from 'src/utils/axios'; // import { AuthContext } from './auth-context'; import { isValidToken, setSession } from './utils'; import { ActionMapType, AuthStateType } from '../../types'; import { IUserItem } from '../../../types/user'; // ---------------------------------------------------------------------- // NOTE: // We only build demo at basic level. // Customer will need to do some extra handling yourself if you want to extend the logic and other features... // ---------------------------------------------------------------------- enum Types { INITIAL = 'INITIAL', LOGIN = 'LOGIN', REGISTER = 'REGISTER', LOGOUT = 'LOGOUT', } type Payload = { [Types.INITIAL]: { user: IUserItem | null; }; [Types.LOGIN]: { user: IUserItem; }; [Types.REGISTER]: { user: IUserItem; }; [Types.LOGOUT]: undefined; }; type ActionsType = ActionMapType<Payload>[keyof ActionMapType<Payload>]; // ---------------------------------------------------------------------- const initialState: AuthStateType = { user: null, loading: true, }; const reducer = (state: AuthStateType, action: ActionsType) => { if (action.type === Types.INITIAL) { return { loading: false, user: action.payload.user, }; } if (action.type === Types.LOGIN) { return { ...state, user: action.payload.user, }; } if (action.type === Types.REGISTER) { return { ...state, user: action.payload.user, }; } if (action.type === Types.LOGOUT) { return { ...state, user: null, }; } return state; }; // ---------------------------------------------------------------------- const STORAGE_KEY = 'accessToken'; type Props = { children: React.ReactNode; }; export function AuthProvider({ children }: Props) { const [state, dispatch] = useReducer(reducer, initialState); const initialize = useCallback(async () => { try { const accessToken = sessionStorage.getItem(STORAGE_KEY); if (accessToken && isValidToken(accessToken)) { setSession(accessToken); const response = await axios.get(endpoints.auth.me); const { user } = response.data; dispatch({ type: Types.INITIAL, payload: { user, }, }); } else { dispatch({ type: Types.INITIAL, payload: { user: null, }, }); } } catch (error) { console.error(error); dispatch({ type: Types.INITIAL, payload: { user: null, }, }); } }, []); useEffect(() => { initialize(); }, [initialize]); // LOGIN const login = useCallback(async (email: string, password: string) => { const data = { email, password, }; const response = await axios.post(endpoints.auth.login, data); const { accessToken, user } = response.data; console.log('SLAT logging in response', user); setSession(accessToken); dispatch({ type: Types.LOGIN, payload: { user, }, }); }, []); // REGISTER const register = useCallback( async (email: string, password: string, firstName: string, lastName: string) => { const data = { email, password, firstName, lastName, }; const response = await axios.post(endpoints.auth.register, data); const { accessToken, user } = response.data; sessionStorage.setItem(STORAGE_KEY, accessToken); dispatch({ type: Types.REGISTER, payload: { user, }, }); }, [] ); // LOGOUT const logout = useCallback(async () => { setSession(null); dispatch({ type: Types.LOGOUT, }); }, []); // ---------------------------------------------------------------------- const checkAuthenticated = state.user ? 'authenticated' : 'unauthenticated'; const status = state.loading ? 'loading' : checkAuthenticated; const memoizedValue = useMemo( () => ({ user: state.user, method: 'jwt', loading: status === 'loading', authenticated: status === 'authenticated', unauthenticated: status === 'unauthenticated', // login, register, logout, }), [login, logout, register, state.user, status] ); return <AuthContext.Provider value={memoizedValue}>{children}</AuthContext.Provider>; }