mirror of
https://github.com/supabase/supabase.git
synced 2026-10-10 20:05:06 +03:00
168 lines
3.7 KiB
TypeScript
168 lines
3.7 KiB
TypeScript
import { Session } from '@supabase/supabase-js'
|
|
import { useProfileQuery } from 'data/profile/profile-query'
|
|
import { useStore } from 'hooks'
|
|
import { auth } from 'lib/gotrue'
|
|
import {
|
|
createContext,
|
|
PropsWithChildren,
|
|
useCallback,
|
|
useContext,
|
|
useEffect,
|
|
useMemo,
|
|
useState,
|
|
} from 'react'
|
|
import { GOTRUE_ERRORS, IS_PLATFORM } from './constants'
|
|
|
|
const DEFAULT_SESSION: any = {
|
|
access_token: undefined,
|
|
expires_at: 0,
|
|
expires_in: 0,
|
|
refresh_token: '',
|
|
token_type: '',
|
|
user: {
|
|
aud: '',
|
|
app_metadata: {},
|
|
confirmed_at: '',
|
|
created_at: '',
|
|
email: '',
|
|
email_confirmed_at: '',
|
|
id: '',
|
|
identities: [],
|
|
last_signed_in_at: '',
|
|
phone: '',
|
|
role: '',
|
|
updated_at: '',
|
|
user_metadata: {},
|
|
},
|
|
}
|
|
|
|
/* Auth Context */
|
|
|
|
export type AuthContext = { refreshSession: () => Promise<Session | null> } & (
|
|
| {
|
|
session: Session
|
|
isLoading: false
|
|
}
|
|
| {
|
|
session: null
|
|
isLoading: boolean
|
|
}
|
|
)
|
|
|
|
export const AuthContext = createContext<AuthContext>({
|
|
session: null,
|
|
isLoading: true,
|
|
refreshSession: () => Promise.resolve(null),
|
|
})
|
|
|
|
export type AuthProviderProps = {}
|
|
|
|
export const AuthProvider = ({ children }: PropsWithChildren<AuthProviderProps>) => {
|
|
const { ui } = useStore()
|
|
const [session, setSession] = useState<Session | null>(null)
|
|
const [isLoading, setIsLoading] = useState(true)
|
|
|
|
// Check for unverified GitHub users after a GitHub sign in
|
|
useEffect(() => {
|
|
async function handleEmailVerificationError() {
|
|
const { error } = await auth.initialize()
|
|
|
|
if (error?.message === GOTRUE_ERRORS.UNVERIFIED_GITHUB_USER) {
|
|
ui.setNotification({
|
|
category: 'error',
|
|
message:
|
|
'Please verify your email on GitHub first, then reach out to us at support@supabase.io to log into the dashboard',
|
|
})
|
|
}
|
|
}
|
|
|
|
handleEmailVerificationError()
|
|
}, [])
|
|
|
|
// Setup a possible existing session
|
|
useEffect(() => {
|
|
let mounted = true
|
|
|
|
auth
|
|
.getSession()
|
|
.then(({ data: { session } }) => {
|
|
if (mounted) {
|
|
if (session) {
|
|
setSession(session)
|
|
}
|
|
|
|
setIsLoading(false)
|
|
}
|
|
})
|
|
.catch(() => {
|
|
if (mounted) {
|
|
setIsLoading(false)
|
|
}
|
|
})
|
|
|
|
return () => {
|
|
mounted = false
|
|
}
|
|
}, [])
|
|
|
|
// Keep the session in sync
|
|
useEffect(() => {
|
|
const {
|
|
data: { subscription },
|
|
} = auth.onAuthStateChange((_event, session) => {
|
|
setSession(session)
|
|
setIsLoading(false)
|
|
})
|
|
|
|
return subscription.unsubscribe
|
|
}, [])
|
|
|
|
// Track telemetry for the current user
|
|
useProfileQuery({
|
|
onSuccess(profile) {
|
|
ui.setProfile(profile)
|
|
},
|
|
// Never rerun the query
|
|
staleTime: Infinity,
|
|
cacheTime: Infinity,
|
|
})
|
|
|
|
// Helper method to refresh the session.
|
|
// For example after a user updates their profile
|
|
const refreshSession = useCallback(async () => {
|
|
const {
|
|
data: { session },
|
|
} = await auth.refreshSession()
|
|
|
|
return session
|
|
}, [])
|
|
|
|
const value = useMemo(() => {
|
|
if (IS_PLATFORM) {
|
|
if (session) {
|
|
return { session, isLoading: false, refreshSession } as const
|
|
} else {
|
|
return { session: null, isLoading: isLoading, refreshSession } as const
|
|
}
|
|
} else {
|
|
return { session: DEFAULT_SESSION, isLoading: false, refreshSession } as const
|
|
}
|
|
}, [session, isLoading, refreshSession])
|
|
|
|
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
|
|
}
|
|
|
|
/* Auth Utils */
|
|
|
|
export const useAuth = () => useContext(AuthContext)
|
|
|
|
export const useSession = () => useAuth().session
|
|
|
|
export const useUser = () => useSession()?.user ?? null
|
|
|
|
export const useIsLoggedIn = () => {
|
|
const user = useUser()
|
|
|
|
return user !== null
|
|
}
|