feat(frontend): Refactor auth and split into separate files
This commit is contained in:
130
legalconsenthub/composables/auth/useAuthState.ts
Normal file
130
legalconsenthub/composables/auth/useAuthState.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import type { ClientOptions, InferSessionFromClient, InferUserFromClient } from 'better-auth/client'
|
||||
import type { RuntimeAuthConfig } from '~/types/auth'
|
||||
import { defu } from 'defu'
|
||||
import { useAuthClient } from '~/composables/auth/useAuthClient'
|
||||
|
||||
// Global state for auth
|
||||
const session = ref<InferSessionFromClient<ClientOptions> | null>(null)
|
||||
const user = ref<InferUserFromClient<ClientOptions> | null>(null)
|
||||
const sessionFetching = import.meta.server ? ref(false) : ref(false)
|
||||
const jwt = ref<string | null>(null)
|
||||
const organizations = ref<
|
||||
{
|
||||
id: string
|
||||
name: string
|
||||
createdAt: Date
|
||||
slug: string
|
||||
metadata?: Record<string, unknown>
|
||||
logo?: string | null
|
||||
}[]
|
||||
>([])
|
||||
const selectedOrganization = ref<{
|
||||
id: string
|
||||
name: string
|
||||
createdAt: Date
|
||||
slug: string
|
||||
metadata?: Record<string, unknown>
|
||||
logo?: string | null
|
||||
} | null>(null)
|
||||
const activeMember = ref<{ role: string } | null>(null)
|
||||
|
||||
export function useAuthState() {
|
||||
const { client } = useAuthClient()
|
||||
const route = useRoute()
|
||||
|
||||
const options = defu(useRuntimeConfig().public.auth as Partial<RuntimeAuthConfig>, {
|
||||
redirectUserTo: '/',
|
||||
redirectGuestTo: '/login'
|
||||
})
|
||||
|
||||
const headers = import.meta.server ? useRequestHeaders() : undefined
|
||||
|
||||
async function fetchSession(targetPath?: string) {
|
||||
if (sessionFetching.value) {
|
||||
console.log('already fetching session')
|
||||
return
|
||||
}
|
||||
sessionFetching.value = true
|
||||
const { data } = await client.getSession({
|
||||
fetchOptions: {
|
||||
headers
|
||||
}
|
||||
})
|
||||
session.value = data?.session || null
|
||||
user.value = data?.user || null
|
||||
sessionFetching.value = false
|
||||
|
||||
// Only fetch JWT and organizations if we have a session and not on public routes
|
||||
if (session.value && !isPublicPath(targetPath)) {
|
||||
await fetchJwtAndOrganizations()
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
async function fetchJwtAndOrganizations() {
|
||||
// Fetch JWT
|
||||
const tokenResult = await client.token()
|
||||
jwt.value = tokenResult.data?.token ?? null
|
||||
|
||||
// Fetch organization
|
||||
const orgResult = await client.organization.list({
|
||||
fetchOptions: {
|
||||
headers
|
||||
}
|
||||
})
|
||||
organizations.value = orgResult.data ?? []
|
||||
|
||||
if (!selectedOrganization.value && organizations.value.length > 0) {
|
||||
selectedOrganization.value = organizations.value[0]
|
||||
}
|
||||
|
||||
// Fetch active member
|
||||
const activeMemberResult = await client.organization.getActiveMember({
|
||||
fetchOptions: {
|
||||
headers
|
||||
}
|
||||
})
|
||||
activeMember.value = activeMemberResult.data || null
|
||||
}
|
||||
|
||||
function isPublicPath(path?: string) {
|
||||
const finalPath = path ?? route.path
|
||||
const publicRoutes = ['/login', '/signup', '/accept-invitation']
|
||||
return publicRoutes.some((path) => finalPath.startsWith(path))
|
||||
}
|
||||
|
||||
// Watch organization changes
|
||||
watch(
|
||||
() => selectedOrganization.value,
|
||||
async (newValue) => {
|
||||
if (newValue) {
|
||||
await client.organization.setActive({
|
||||
organizationId: newValue?.id
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// Client-side session listening
|
||||
if (import.meta.client) {
|
||||
client.$store.listen('$sessionSignal', async (signal) => {
|
||||
if (!signal) return
|
||||
await fetchSession()
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
session,
|
||||
user,
|
||||
sessionFetching,
|
||||
jwt,
|
||||
organizations,
|
||||
selectedOrganization,
|
||||
activeMember,
|
||||
options,
|
||||
fetchSession,
|
||||
isPublicPath,
|
||||
loggedIn: computed(() => !!session.value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user