Files
nuzlocke-tracker/frontend/src/contexts/AuthContext.tsx

94 lines
2.8 KiB
TypeScript
Raw Normal View History

import { createContext, useContext, useEffect, useState, useCallback, useMemo } from 'react'
import type { User, Session, AuthError } from '@supabase/supabase-js'
import { supabase } from '../lib/supabase'
interface AuthState {
user: User | null
session: Session | null
loading: boolean
}
interface AuthContextValue extends AuthState {
signInWithEmail: (email: string, password: string) => Promise<{ error: AuthError | null }>
signUpWithEmail: (email: string, password: string) => Promise<{ error: AuthError | null }>
signInWithGoogle: () => Promise<{ error: AuthError | null }>
signInWithDiscord: () => Promise<{ error: AuthError | null }>
signOut: () => Promise<void>
}
const AuthContext = createContext<AuthContextValue | null>(null)
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [state, setState] = useState<AuthState>({
user: null,
session: null,
loading: true,
})
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setState({ user: session?.user ?? null, session, loading: false })
})
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((_event, session) => {
setState({ user: session?.user ?? null, session, loading: false })
})
return () => subscription.unsubscribe()
}, [])
const signInWithEmail = useCallback(async (email: string, password: string) => {
const { error } = await supabase.auth.signInWithPassword({ email, password })
return { error }
}, [])
const signUpWithEmail = useCallback(async (email: string, password: string) => {
const { error } = await supabase.auth.signUp({ email, password })
return { error }
}, [])
const signInWithGoogle = useCallback(async () => {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: `${window.location.origin}/auth/callback` },
})
return { error }
}, [])
const signInWithDiscord = useCallback(async () => {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'discord',
options: { redirectTo: `${window.location.origin}/auth/callback` },
})
return { error }
}, [])
const signOut = useCallback(async () => {
await supabase.auth.signOut()
}, [])
const value = useMemo(
() => ({
...state,
signInWithEmail,
signUpWithEmail,
signInWithGoogle,
signInWithDiscord,
signOut,
}),
[state, signInWithEmail, signUpWithEmail, signInWithGoogle, signInWithDiscord, signOut]
)
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
}
export function useAuth() {
const context = useContext(AuthContext)
if (!context) {
throw new Error('useAuth must be used within an AuthProvider')
}
return context
}