import { createContext, useContext, useSyncExternalStore } from "react"; import { onAuthStateChanged, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut, sendEmailVerification as firebaseSendEmailVerification, } from "firebase/auth"; import { auth } from "../firebase/config"; import { getAccount } from "../api/account"; const AuthContext = createContext(undefined); const DEFAULT_TIER_LIMITS = { max_addresses: 1, max_alert_types: 1, allowed_channels: ["email"], }; // External auth store - lives outside React const createAuthStore = () => { let state = { currentUser: null, userTier: "free", tierLimits: DEFAULT_TIER_LIMITS, isSubscribed: false, loading: true, }; const listeners = new Set(); const notify = () => listeners.forEach((fn) => fn()); const setState = (partial) => { state = { ...state, ...partial }; notify(); }; const fetchAccount = async () => { try { const data = await getAccount(); setState({ userTier: data.subscription_tier || "free", tierLimits: data.tier_limits || DEFAULT_TIER_LIMITS, isSubscribed: data.subscription_status === "active" || data.subscription_status === "trialing", }); } catch { setState({ isSubscribed: false }); } }; // Set up Firebase listener once, outside of React onAuthStateChanged(auth, async (user) => { setState({ loading: true, currentUser: user }); if (user) { await fetchAccount(); } else { setState({ isSubscribed: false, userTier: "free", tierLimits: DEFAULT_TIER_LIMITS }); } setState({ loading: false }); }); return { subscribe: (listener) => { listeners.add(listener); return () => listeners.delete(listener); }, getSnapshot: () => state, refreshAccount: fetchAccount, }; }; const authStore = createAuthStore(); export function AuthProvider({ children }) { const state = useSyncExternalStore(authStore.subscribe, authStore.getSnapshot); const signup = (email, password) => createUserWithEmailAndPassword(auth, email, password); const login = (email, password) => signInWithEmailAndPassword(auth, email, password); const logout = () => signOut(auth); const sendEmailVerification = () => { if (auth.currentUser) { return firebaseSendEmailVerification(auth.currentUser); } }; const reloadUser = async () => { if (auth.currentUser) { await auth.currentUser.reload(); return auth.currentUser; } return null; }; const value = { ...state, signup, login, logout, sendEmailVerification, reloadUser, refreshAccount: authStore.refreshAccount, }; return ( {!state.loading && children} ); } export function useAuth() { const context = useContext(AuthContext); if (context === undefined) { throw new Error("useAuth must be used within an AuthProvider"); } return context; } export default useAuth;