import { supabase } from '@/utils/supabase/supabase'
import { AppState, AppStateStatus } from 'react-native'
import type { Session, User } from '@supabase/supabase-js'
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
// Tells Supabase Auth to continuously refresh the session automatically if
// the app is in the foreground. When this is added, you will continue to receive
// `onAuthStateChange` events with the `TOKEN_REFRESHED` or `SIGNED_OUT` event
// if the user's session is terminated. This should only be registered once.
// AppState.addEventListener('change', state => {
// if (state === 'active') {
// supabase.auth.startAutoRefresh()
// } else {
// supabase.auth.stopAutoRefresh()
// }
// })
type AuthContextValue = {
isAuthLoading: boolean
isAuthenticated: boolean
session: Session | null
user: User | null
signInWithEmailAndPassword: (email: string, password: string) => Promise<{ data: { user: User | null; session: Session | null } | null; error: any }>
signOut: () => Promise<{ error: any }>
}
const SupabaseAuthContext = createContext(null)
export default function SupabaseAuthProvider({ children }: { children: React.ReactNode }) {
const [isAuthLoading, setIsAuthLoading] = useState(false)
const [session, setSession] = useState(null)
const [user, setUser] = useState(null)
const isAuthenticated = !!(session && user)
// 1) Initial load + auth change subscription
useEffect(() => {
let mounted = true
;(async () => {
const { data, error } = await supabase.auth.getSession()
if (!mounted) return
if (!error) {
setSession(data.session ?? null)
setUser(data.session?.user ?? null)
}
setIsAuthLoading(false)
})()
const { data: sub } = supabase.auth.onAuthStateChange((_event, newSession) => {
setSession(newSession)
setUser(newSession?.user ?? null)
})
return () => {
mounted = false
sub?.subscription?.unsubscribe?.()
}
}, [])
// 2) Auto refresh while app is active (with cleanup)
useEffect(() => {
const handleAppState = (state: AppStateStatus) => {
if (state === 'active') {
supabase.auth.startAutoRefresh()
} else {
supabase.auth.stopAutoRefresh()
}
}
const sub = AppState.addEventListener('change', handleAppState)
// start immediately if already active
handleAppState(AppState.currentState)
return () => {
supabase.auth.stopAutoRefresh()
sub.remove()
}
}, [])
async function signInWithEmailAndPassword(email: string, password: string) {
// setIsAuthLoading(true)
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
})
if (data || !error) {
setSession(data.session)
setUser(data.user)
}
// setIsAuthLoading(false)
return { data, error }
}
async function signOut() {
// setIsAuthLoading(true)
const { error } = await supabase.auth.signOut()
if (!error) {
setSession(null)
setUser(null)
}
return { error }
}
const value = useMemo(
() => ({
isAuthLoading,
isAuthenticated,
session,
user,
signInWithEmailAndPassword,
signOut,
}),
[isAuthLoading, isAuthenticated, session, user]
)
return {children}
}
export const useSupabaseAuth = () => {
const context = useContext(SupabaseAuthContext)
if (!context) throw new Error('useSupabaseAuth must be used within SupabaseAuthProvider')
return context
}