import { type Auth, connectAuthEmulator, getAuth, OAuthProvider, onAuthStateChanged, signInWithPopup, signOut, type User, type UserCredential, } from 'firebase/auth'; import { createContext, type ReactNode, useContext, useEffect, useState, } from 'react'; import { useFirebaseApp } from './FirebaseAppProvider'; type AuthContextValue = { auth: Auth; provider: OAuthProvider; currentUser?: User; login(): Promise; logout(): Promise; ready: boolean; }; type FirebaseAuthProviderProps = { provider: OAuthProvider; children: ReactNode; bypassEmulator?: boolean; // useful for testing against real cloud auth endpoints }; const FirebaseAuthContext = createContext(null); export const FirebaseAuthProvider = (props: FirebaseAuthProviderProps) => { const { provider } = props; const app = useFirebaseApp(); const sdk = getAuth(app); const [currentUser, setCurrentUser] = useState(); const [ready, setReady] = useState(false); if (!app) { throw new Error( 'You cannot use the FirebaseAuthProvider outside of a ', ); } useEffect(() => { const unsubscribe = onAuthStateChanged(sdk, (user) => { setCurrentUser(user ?? undefined); }); sdk.authStateReady().finally(() => setReady(true)); return () => unsubscribe(); }, [sdk]); // @see https://firebase.google.com/docs/auth/web/google-signin const login = () => signInWithPopup(sdk, provider); const logout = () => signOut(sdk); useEffect(() => { if (app && import.meta.env.DEV && !props.bypassEmulator) { const auth = getAuth(app); if (!auth.emulatorConfig) { console.log('Connecting to Firebase Authentication emulator'); connectAuthEmulator(auth, 'http://127.0.0.1:9099', { disableWarnings: true, }); } } }, [app, props.bypassEmulator]); return ( ); }; export const useFirebaseAuth = () => { const value = useContext(FirebaseAuthContext); if (value === null) { throw new Error( 'useFirebaseAuth must be used within a FirebaseAuthProvider', ); } return value; };