Spaces:
Sleeping
Sleeping
| import React, { createContext, useContext, useState, useEffect } from 'react'; | |
| const AuthContext = createContext(null); | |
| export function AuthProvider({ children }) { | |
| const [user, setUser] = useState(null); | |
| const [token, setToken] = useState(() => localStorage.getItem('access_token')); | |
| const [loading, setLoading] = useState(true); | |
| // On mount β verify stored token by hitting /api/auth/me | |
| useEffect(() => { | |
| if (!token) { setLoading(false); return; } | |
| fetch('/api/auth/me', { | |
| headers: { Authorization: `Bearer ${token}` }, | |
| }) | |
| .then(r => r.ok ? r.json() : Promise.reject()) | |
| .then(data => setUser(data)) | |
| .catch(() => { | |
| // Token invalid / expired β clear it | |
| localStorage.removeItem('access_token'); | |
| localStorage.removeItem('refresh_token'); | |
| setToken(null); | |
| }) | |
| .finally(() => setLoading(false)); | |
| }, [token]); | |
| // ββ Register ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async function register(name, email, password) { | |
| const res = await fetch('/api/auth/register', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ name, email, password }), | |
| }); | |
| const data = await res.json(); | |
| if (!res.ok) throw new Error(data.error || 'Registration failed.'); | |
| localStorage.setItem('access_token', data.access_token); | |
| localStorage.setItem('refresh_token', data.refresh_token); | |
| setToken(data.access_token); | |
| setUser(data.user); | |
| return data; | |
| } | |
| // ββ Login βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async function login(email, password) { | |
| const res = await fetch('/api/auth/login', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ email, password }), | |
| }); | |
| const data = await res.json(); | |
| if (!res.ok) throw new Error(data.error || 'Login failed.'); | |
| localStorage.setItem('access_token', data.access_token); | |
| localStorage.setItem('refresh_token', data.refresh_token); | |
| setToken(data.access_token); | |
| setUser(data.user); | |
| return data; | |
| } | |
| // ββ Logout ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function logout() { | |
| localStorage.removeItem('access_token'); | |
| localStorage.removeItem('refresh_token'); | |
| setToken(null); | |
| setUser(null); | |
| } | |
| // ββ Authenticated fetch helper βββββββββββββββββββββββββββββββββββββββββββββββ | |
| // Use this instead of plain fetch() for protected API calls. | |
| async function authFetch(url, options = {}) { | |
| const headers = { | |
| ...(options.headers || {}), | |
| Authorization: `Bearer ${localStorage.getItem('access_token')}`, | |
| }; | |
| return fetch(url, { ...options, headers }); | |
| } | |
| return ( | |
| <AuthContext.Provider value={{ user, token, loading, login, logout, register, authFetch }}> | |
| {children} | |
| </AuthContext.Provider> | |
| ); | |
| } | |
| // Hook for easy access | |
| export function useAuth() { | |
| return useContext(AuthContext); | |
| } |