| import React, { |
| createContext, |
| useCallback, |
| useContext, |
| useEffect, |
| useMemo, |
| useState, |
| } from 'react'; |
| import { apiFetch } from '@/lib/api'; |
|
|
| const AuthContext = createContext(null); |
|
|
| export function AuthProvider({ children }) { |
| const [phase, setPhase] = useState('loading'); |
| const [googleOn, setGoogleOn] = useState(false); |
| const [user, setUser] = useState(null); |
|
|
| const refresh = useCallback(async () => { |
| try { |
| const [st, meRes] = await Promise.all([ |
| apiFetch('/api/auth/status').then((r) => r.json()), |
| apiFetch('/api/auth/me'), |
| ]); |
| setGoogleOn(!!st.googleConfigured); |
| setUser(meRes.ok ? await meRes.json() : null); |
| setPhase('ready'); |
| } catch { |
| setPhase('error'); |
| } |
| }, []); |
|
|
| useEffect(() => { |
| refresh(); |
| }, [refresh]); |
|
|
| useEffect(() => { |
| const onAuth = () => refresh(); |
| window.addEventListener('emailout-auth-changed', onAuth); |
| return () => window.removeEventListener('emailout-auth-changed', onAuth); |
| }, [refresh]); |
|
|
| const value = useMemo( |
| () => ({ |
| phase, |
| googleOn, |
| user, |
| signedIn: !!user, |
| refresh, |
| }), |
| [phase, googleOn, user, refresh] |
| ); |
|
|
| return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>; |
| } |
|
|
| export function useAuth() { |
| const ctx = useContext(AuthContext); |
| if (!ctx) { |
| throw new Error('useAuth must be used within AuthProvider'); |
| } |
| return ctx; |
| } |
|
|