Authentication Documentation

Filename src\app\contexts\AuthContext.tsx

This file handles all user authentification SignUp,SignIn,SignOut and PasswordReset


1. Global file imports

"use client"
import {useEffect,useState, useContext , createContext, ReactNode } from "react";
import { 
    onAuthStateChanged,
    signInWithEmailAndPassword,
    createUserWithEmailAndPassword,
    sendEmailVerification,
    signOut,
    sendPasswordResetEmail
 } from "firebase/auth";
 import { doc, setDoc, getDoc } from "firebase/firestore";
import { auth } from "../firebase";
import { toast} from "sonner";
import { useRouter } from "next/navigation";
import { db } from "../firebase";
 

useEffect,useState: are react hooks for state management

useContext,createContext: are react hooks to publish and create context API’s

ReactNode:a typescipt type that represends anything react can render

createUserWithEmailAndPassword:a firebase function that create a new user given and email and password

signInWithEmailAndPassword:a firebase function that authenticates a user given email and password exist

signOut:a firebase function that Logs the current user out of the application.

sendPasswordResetEmai:a firebase function that send an email link to reset password when email provided exists

sendEmailVerification:a firebase function that send verification email when user first signs up

onAuthStateChanged:a firebase function that listens for user state change

doc: a function that create a reference to the named document

setDoc: a function that add information to the named document and overwrites preexisting data

getDoc: a function that retrieves contents of the named document

auth: auth instance from firebase

Toast: function from the Sonner library, a React-based toast notification library.

useReducer:a react hook that enables programmatic navigation between paged

db: database instance from the firebase


2. Interface Declaration

interface AuthContextProps {
    //updated
    user:any
    userInfo: UserInfo
    signUp : (profile:any)=>Promise<void>,
    signIn : (profile:any)=>Promise<void>,
    signOutUser : ()=>Promise<void>,
    passwordReset :(email:string)=>Promise<void>,
    isloading:boolean
}

AuthContextProps:Defines a blueprint of the shape the object should take


2b. Interface Declaration

interface AuthProviderProps{
    children:ReactNode
}

AuthProviderProps:Reprents every react element


2c. Interface Declaration

interface UserInfo {
    fullname: string;
    email: string;
}

UserInfo:Defines blueprint of the user object


3. Context Creation

const AuthContext = createContext<AuthContextProps|undefined>(undefined)
 

AuthContet:It an instance of the context , that is export to other files


4. SignUp function

const signUp = async(profile:any)=>{
        try{
            setIsloading(true)
            console.log(profile)
            const userCredential = await createUserWithEmailAndPassword(auth , profile.email , profile.passWord)
            const user = userCredential.user
            await sendEmailVerification(user)
            setIsloading(false)
            toast.success("Sign up successful! Verification email sent..") 
            createUserDB(profile.firstName , profile.lastName , profile.email)
        }catch(error:any){
            setIsloading(false)
            toast.error("Signup Error")
            console.log(error.message)
        }
    }

signUp

  1. Takes in profile argument that has (firstName,lastName,email,password)

  2. Creates a user in the firebase Auth by passing email and password to the createUserWithEmailandPassword function

  3. Sends verification to email via the sendEmailVerification

  4. Adds user to that has (firstName,lastName,email) in user database

  5. Then toast success message


5. SignIn function

const signIn = async (profile: any) => {
        try {
            console.log(profile);
            setIsloading(true);
            const userCredential = await signInWithEmailAndPassword(auth, profile.email, profile.passWord);
            const user = userCredential.user;
    
            if (user.emailVerified) {
                // Handle successful sign-in without navigation
                toast.success("Sign-in successful");
            } else {
                toast.warning("Verify your email please");
            }
            setIsloading(false);
        } catch (error: any) {
            setIsloading(false);
            toast.error("Admin does not exist");
        }
    };
  1. Takes in profile argument that has (email,password)

  2. Checks if email is verified via user.emailVerified

  3. Checks if user exist and return userToken via signInUserWithEmailAndPassword


6. SignOut function

const signOutUser  = async()=>{
        try{
            await signOut(auth)
            setUser(null); // Reset user state
            toast.success("Signed out successfully!");
         }catch(error:any){
            toast.error(error.message)
        }
    }
  1. Takes in the available auth as argument

  2. Removes the auth via signOut


7. Password Reset Function

const passwordReset = async(email:string)=>{
        try{
            setIsloading(true)
            await sendPasswordResetEmail(auth , email)
            setIsloading(false)
            toast.success("Password reset email sent! Check your inbox.")
        }catch(error:any){
            setIsloading(false)
            toast.error(error.message)
        }
    }
  1. Takes in auth and email

  2. Sends reset email if if email exists in auth


8. UserDB Creation

const createUserDB =async(firstname:string , lastname:string , documentname:string)=>{
        await setDoc(doc(db , "users" , documentname),{
            fullname :`${firstname} ${lastname}`,
            email :`${documentname}`
        })
        setUserInfo({
            fullname :`${firstname} ${lastname}`,
            email :`${documentname}`
        })
       
    }
  1. Takes in (firstName,lastName and documentName) as argurments

  2. Create a new user in the document with documentName


9. fetchUser Function

const fetchUser = async(documentname:string)=>{
        try{
            const docsnap = await getDoc(doc(db,"users" , documentname))
            if(docsnap.exists()){
                setUserInfo(docsnap.data())
            }else{
                toast.error("user not fould!")
            }
        }catch(error){
            toast.error("falied to fetch user from userDB")
        }
    }
  1. Fetches user from documentname

10.React Hook

useEffect(() => {      
        const unsubscribe = onAuthStateChanged(auth, (user) => {
            setUser(user);
            if (user) {
                fetchUser(user.email || "");
            } else {
                setUserInfo(null); 
            }
          
        });  
        return () => unsubscribe();
    }, []);
    
  1. listens for auth change

11. Context export

export const useAuth = ()=>{
    const context = useContext(AuthContext) 
    if(!context){
        throw new Error("Error with useAuth")
    }
    return context
}
  1. Exports the AuthContext

12. Main Function

export const AuthProvider  = ({children}:AuthProviderProps)=>{
    const router = useRouter()
    const [user, setUser] = useState<any>(null); 
    const [userInfo , setUserInfo] =useState<any>(null)
    const [isloading , setIsloading] = useState<boolean>(false)
 
    
    
    const values ={
        signUp,
        signIn,
        signOutUser,
        passwordReset,
        user,
        userInfo,
        isloading
    }
 
    return(
    <AuthContext.Provider value={values} >
        {children}
    </AuthContext.Provider>
    )
}

values : Exports instances of the authContext

[user, setUser] :Stores user state in the authContext.tsx

[userInfo , setUserInfo] :Stores userInfo state in the authContext.tsx

[isloading , setIsloading] :Stores isloading state in the authContext.tsx