import { UserDocument } from '@waves/shared' ; import React , { FC , createContext , useEffect , useState } from 'react' ; import { useCreateToast } from '../components' ; import { analytics , firebase } from '../config/firebase' ; type UnauthedState = { isAuthed : false ; isLoading : boolean ; user : null ; token : undefined ; } ; type AuthedState = { isAuthed : true ; isLoading : boolean ; user : UserDocument ; token : string ; } ; export type AuthState = UnauthedState | AuthedState ; export type AuthDispatch = { logout : ( ) => Promise < void > ; } ; export const initialAuthState = { isAuthed : false , isLoading : true , user : null , token : undefined , } ; const AuthStateContext = createContext < AuthState > ( initialAuthState ) ; const AuthDispatchContext = createContext < AuthDispatch > ( { logout : ( ) => Promise . resolve ( ) , } ) ; export const AuthProvider = ( { children } ) => { const [ authState , setAuthState ] = useState < AuthState > ( initialAuthState ) ; const toast = useCreateToast ( ) ; useEffect ( ( ) => { let unsubscribeFromUserListener = ( ) => { } ; const unsubscribe = firebase . auth ( ) . onAuthStateChanged ( async ( userAuth ) => { if ( ! userAuth ) { setAuthState ( { isAuthed : false , isLoading : false , user : null , token : undefined , } ) ; } else { analytics . setUserId ( userAuth . uid ) ; const db = firebase . firestore ( ) ; unsubscribeFromUserListener = await db . collection ( 'users' ) . doc ( userAuth . uid ) . onSnapshot ( async ( doc ) => { const userInfo = doc . data ( ) as UserDocument ; const token = await firebase . auth ( ) ?. currentUser ?. getIdToken ( ) ; if ( userInfo ) { analytics . setUserProperties ( { tier : userInfo . tier } ) ; setAuthState ( { isAuthed : true , isLoading : false , user : userInfo , token , } ) ; } } , ( e ) => { toast ( `Error: ${ e . message }` ) ; } ) ; } } ) ; return ( ) => { unsubscribe ( ) ; unsubscribeFromUserListener ( ) ; } ; } , [ ] ) ; return ( < AuthStateContext . Provider value = { authState } > < AuthDispatchContext . Provider value = { { logout : async ( ) => { await firebase . auth ( ) . signOut ( ) ; window . location . href = '/' ; } , } } > { children } < /AuthDispatchContext.Provider> < /AuthStateContext.Provider>); } ; export const useAuthState = ( ) => { const context = React . useContext ( AuthStateContext ) ; if ( context === undefined ) { throw new Error ( 'useAuthState must be used within a AuthProvider' ) ; } return context ; } ; export const useAuthDispatch = ( ) => { const context = React . useContext ( AuthDispatchContext ) ; if ( context === undefined ) { throw new Error ( 'useAuthDispatch must be used within a AuthProvider' ) ; } return context ; } ;