import React, { createContext, useContext, useEffect, useState } from 'react'; import { auth, initializeFirebase } from '../../config/firebase'; import { initMockAuth, mockAuth } from '../../config/mockAuth'; import { authService } from './authService'; import { AuthContextType, AuthViewer } from './types'; const AuthContext = createContext(undefined); export const useAuthContext = () => { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuthContext must be used within an AuthProvider'); } return context; }; interface AuthProviderProps { children: React.ReactNode; } export const AuthProvider: React.FC = ({ children }) => { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { let unsubscribe: (() => void) | undefined; initializeFirebase().then(() => { // No Firebase config — subscribe to the persona-backed mock instead of // rendering signed-out forever, so the app can be viewed as each persona. if (!auth) { // Subscribe first: the listener fires immediately with the current // (signed-out) state so the app paints, then again once the roster has // arrived and a persisted session is restored. unsubscribe = mockAuth.onAuthStateChanged((mockUser) => { setUser(mockUser); setLoading(false); }); void initMockAuth(); return; } unsubscribe = auth.onAuthStateChanged((firebaseUser) => { setUser(firebaseUser); setLoading(false); }); }); return () => unsubscribe?.(); }, []); const clearError = () => setError(null); const signInWithGoogle = async () => { try { setLoading(true); clearError(); await authService.signInWithGoogle(); } catch (err) { setLoading(false); const firebaseErr = err as { code?: string; message?: string }; const isCancel = firebaseErr.code === 'auth/popup-closed-by-user' || firebaseErr.code === 'auth/cancelled-popup-request' || firebaseErr.code === 'auth/popup-blocked'; if (!isCancel) { setError(firebaseErr.message ?? 'Google sign-in failed'); } } }; const signInWithEmail = async (email: string, password: string) => { try { setLoading(true); clearError(); await authService.signInWithEmail(email, password); } catch (err) { setLoading(false); setError((err as { message?: string }).message ?? 'Sign-in failed'); } }; const signUpWithEmail = async (email: string, password: string, displayName?: string) => { try { setLoading(true); clearError(); await authService.signUpWithEmail(email, password, displayName); } catch (err) { setLoading(false); setError((err as { message?: string }).message ?? 'Sign-up failed'); } }; const sendSignInLinkToEmail = async (email: string) => { try { setLoading(true); clearError(); const actionCodeSettings = { url: `${window.location.origin}/login`, handleCodeInApp: true, }; await authService.sendSignInLinkToEmail(email, actionCodeSettings); setLoading(false); } catch (err) { setLoading(false); setError((err as { message?: string }).message ?? 'Failed to send sign-in link'); } }; const signInWithEmailLink = async (email: string, emailLink: string) => { try { setLoading(true); clearError(); await authService.signInWithEmailLink(email, emailLink); } catch (err) { setLoading(false); setError((err as { message?: string }).message ?? 'Email link sign-in failed'); } }; const isSignInWithEmailLink = (emailLink: string): boolean => { return authService.isSignInWithEmailLink(emailLink); }; const signOut = async () => { try { setLoading(true); await authService.signOut(); setUser(null); setLoading(false); } catch (err) { setLoading(false); setError((err as { message?: string }).message ?? 'Sign-out failed'); } }; const value: AuthContextType = { user, loading, error, signInWithGoogle, signOut, signInWithEmail, signUpWithEmail, sendSignInLinkToEmail, signInWithEmailLink, isSignInWithEmailLink, clearError, }; return {children}; };