import { createContext, useState, useContext, useEffect } from "react"; import * as React from "react"; import { UserApi, UserItem } from "../../types"; type AuthProviderProps = { userApi: UserApi, children?: React.ReactNode } type AuthCredentials = { email: string; password: string; otp?: string | undefined; } type AuthContextProps = { isAuthenticated: boolean, user: UserItem | null; login: (credentials: AuthCredentials) => Promise, register: (credentials: AuthCredentials, userName: string) => Promise, loading: Boolean, logout: () => Promise, updateUser: (user: UserItem) => any, token: String | null, requestPasswordReset: (email:string, reset_url: string) => Promise, passwordReset: (token:string, new_password:string) => Promise } const AuthContext = createContext({ isAuthenticated: false, user: null, login: () => Promise.reject(), register: () => Promise.reject(), loading: false, logout: () => Promise.reject(), updateUser: () => Promise.reject(), token: "", requestPasswordReset: () => Promise.reject(), passwordReset: () => Promise.reject() }); export const AuthProvider = ({ userApi, children }: AuthProviderProps) => { const [user, setUser] = useState(null); const [token, setToken] = useState(null); const [loading, setLoading] = useState(false); const isAuthenticated = !!user; useEffect(() => { setLoading(true); loadUser(); setLoading(false) }, []); async function loadUser(): Promise { try { const token = await userApi.getToken(); setToken(token); if(token){ const me = await userApi.getUser(); setUser(me as UserItem); setLoading(false); return me as UserItem; } else return undefined; } catch (error) { setLoading(false) return undefined; } } const login = async (credentials: AuthCredentials): Promise => { setLoading(true); try { const res = await userApi.login(credentials.email, credentials.password); setToken(res.access_token); return (await loadUser()); } catch (error: any) { setLoading(false); throw error; }; } const register = async (credentials: AuthCredentials, userName): Promise => { setLoading(true); try { const res = await userApi.register(credentials.email, credentials.password, userName) return (await login(credentials)); } catch (error: any) { setLoading(false); throw error; }; } const logout = async () => { try { await userApi.logout(); setUser(null); } catch (error: any) { setLoading(false); throw error; }; } const updateUser = async (user: UserItem) => { setLoading(true); const { id, ...userRest } = user; try { const res = await userApi.updateUser(userRest); setUser(res as any); loadUser(); setLoading(false); return res as any; } catch (error: any) { setLoading(false); throw error; }; } const requestPasswordReset = async (email: string, reset_url?: string): Promise => { setLoading(true); try { await userApi.requestPasswordReset(email, reset_url); return setLoading(false); } catch (error: any) { setLoading(false); throw error; }; } const passwordReset = async (token: string, new_password:string): Promise => { setLoading(true); try { await userApi.passwordReset(token, new_password); return setLoading(false); } catch (error: any) { setLoading(false); throw error; }; } return ( {children} ); }; export const useAuth = () => useContext(AuthContext);