Sherlock / components / authContext.tsx
authContext.tsx
Raw
import { Session, User } from "@supabase/supabase-js"
import { createContext, useContext, useEffect, useState } from "react";
import { supabase } from "./supabase";
import { addDevice, createUser, deviceLogin, deviceLogout, subscribeDefault } from "./backend";
import global from "../constants/global";
import Constants from "expo-constants";
import { Platform } from "react-native";
import * as Application from 'expo-application'


type AuthProps = {
    user: User | null;
    session: Session | null;
    loading: boolean;
    displayName: string | null;
    verified: boolean | null;
    signIn: (email:string, password:string) => Promise<void>;
    signUp: (email:string, password: string) => Promise<void>;
    signOut: () => Promise<void>;
}

interface AuthContextType{

}

export const AuthContext = createContext<AuthProps>({
    user: null,
    session:null,
    loading: true,
    displayName:null,
    verified:false,
    signIn: (email, password)=>{return new Promise<void>(()=>{})},
    signUp: (email, password)=>{return new Promise<void>(()=>{})},
    signOut: ()=>{return new Promise<void>(()=>{})},
})

export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
    const [session, setSession] = useState<Session | null>(null)
    const [user, setUser] = useState<User | null>(null)
    const [loading, setLoading] = useState(true)
    const [displayName, setDisplayName] = useState("")
    const [verified, setVerified] = useState(false)

    useEffect(() => {
        const init = async () => {
            const { data, error } = await supabase.auth.getSession()
            if (data.session) {
                setSession(data.session)
                setUser(data.session.user)
                setVerified(data.session.user.user_metadata.email_verified)
                setDisplayName(data.session.user.user_metadata.full_name)
            }
            setLoading(false)
        }

        init()

        const {
            data: { subscription },
        } = supabase.auth.onAuthStateChange((_event, session) => {
            setSession(session)
            setUser(session?.user ?? null)
            setDisplayName(session?.user.user_metadata.full_name ?? null);
            setVerified(session?.user.user_metadata.email_verified ?? null);
            
            if(session?.user){
                console.log("global token:",global.expoToken)
                deviceLogin(global.expoToken).then(()=>{
                    console.log("Logged in device.",global.expoToken)
                }).catch((error)=>{
                    // Adds device to backend
                    if(error){
                        addDevice(global.expoToken, Constants.deviceName?Constants.deviceName:"None", Application.nativeApplicationVersion?Application.nativeApplicationVersion:"NULL", Platform.OS).then((res)=>{
                            console.log("Logged in device.")
                        }).catch((err)=>{
                            console.error(err)
                        })
                    }
                })
            }
        })

        return () => {
            subscription.unsubscribe()
        }
    }, [])

    const signIn = async (email: string, password: string) => {
        const { error } = await supabase.auth.signInWithPassword({ email, password })
        if (error) throw error
    }

    const signUp = async (email: string, password: string) => {
        const { data,error } = await supabase.auth.signUp({ email, password })
        if (error) throw error

        createUser().then((user) => {
            console.log("User created in Sherlock: ", user);
            console.log("Subscribing user to default notifications")
            subscribeDefault().catch((error)=>{
                console.log("Error subscribing user to default topics.",error)
            })
        }).catch((error) => {
            console.log("Error creating user in Sherlock: ", error);
            throw error;
        })
    }

    const signOut = async () => {
        deviceLogout(global.expoToken).then(async(res)=>{
            const { error } = await supabase.auth.signOut();
            if (error) throw error;

            console.log("Logged out device")
        }).catch((error)=>{
            console.log(error)
        })
    }

    return (
        <AuthContext.Provider value={{ session, user, loading, verified, displayName,  signIn, signUp, signOut }}>
            {children}
        </AuthContext.Provider>
    )
}

export const useAuth = () =>{
    const context = useContext(AuthContext)
    if(!context){
        throw new Error("useAuth must be used within an AuthProvider.")
    }
    return context
}