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
}