import React, { createContext, useContext, useState, useMemo, useEffect, } from "react"; import PropTypes from "prop-types"; const decodeJwtPayload = (token) => JSON.parse(atob(token.split(".")[1])); const AuthContext = createContext(); const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const fetchData = async () => { const jwtToken = localStorage.getItem("token"); if (jwtToken) { try { const decodedPayload = decodeJwtPayload(jwtToken); const res = await fetch( `${import.meta.env.VITE_BACKEND_URL}/api/users/${decodedPayload.user}`, { headers: { "x-auth-token": jwtToken }, } ); if (!res.ok) throw new Error("Failed to fetch user"); const data = await res.json(); setUser(data); } catch (error) { console.error("Error fetching user data:", error); localStorage.removeItem("token"); } finally { setLoading(false); } } else { setLoading(false); } }; fetchData(); }, []); const loginWithOAuth = async (token) => { const res = await fetch( `${import.meta.env.VITE_BACKEND_URL}/api/auth/callback?code=${encodeURIComponent(token)}` ); const data = await res.json(); if (!res.ok) { throw new Error(data.message || "OAuth login failed"); } localStorage.setItem("token", data.token); setUser(data.user); return data.user; }; const logout = () => { localStorage.removeItem("token"); setUser(null); }; const editUser = async (updatedFields) => { try { const response = await fetch( `${import.meta.env.VITE_BACKEND_URL}/api/users/${user.id}`, { method: "PUT", headers: { "Content-Type": "application/json", "x-auth-token": localStorage.getItem("token"), }, body: JSON.stringify(updatedFields), } ); if (response.ok) { const updatedUser = await response.json(); setUser((prevUser) => ({ ...prevUser, ...updatedUser.user, })); return "User updated successfully"; } if (response.status === 400) { console.error("Bad Request:", response.statusText); throw new Error("Bad Request"); } else if (response.status === 401) { console.error("Unauthorized:", response.statusText); throw new Error("Unauthorized"); } else { console.error("Error updating user:", response.statusText); throw new Error("Error updating user"); } } catch (error) { console.error("Error updating user:", error); throw new Error("An error occurred during user update"); } }; const sendPasswordResetEmail = async (email) => { try { const response = await fetch( `${import.meta.env.VITE_BACKEND_URL}/api/forgot-password`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ mail: email }), } ); if (response.ok) { return "Password reset email sent successfully"; } const data = await response.json(); throw new Error(data.message || "Error sending password reset email"); } catch (error) { console.error("Error sending password reset email:", error); throw new Error( "An error occurred while sending the password reset email" ); } }; const authContextValue = useMemo(() => { return { user, loading, logout, loginWithOAuth, editUser, sendPasswordResetEmail, setUser: (newUser) => { setUser(newUser); }, }; }, [user, loading, logout]); return ( {children} ); }; AuthProvider.propTypes = { children: PropTypes.node.isRequired, }; const useAuth = () => { const context = useContext(AuthContext); if (!context) { throw new Error("useAuth must be used within an AuthProvider"); } return context; }; export { AuthProvider, useAuth };