useAuth.ts 1.78 KB
import type { AuthUser } from '~/types'
import { createSharedComposable } from '@vueuse/core'

const AUTH_TOKEN_COOKIE_KEY = 'auth-token'

const _useAuth = () => {
  const tokenCookie = useCookie<string | null>(AUTH_TOKEN_COOKIE_KEY, {
    default: () => null,
    sameSite: 'lax'
  })
  const token = useState<string | null>('auth-token', () => tokenCookie.value ?? null)
  const user = useState<AuthUser | null>('auth-user', () => null)
  const isLoadingUser = useState<boolean>('auth-loading-user', () => false)
  const authApi = useAuthApi()

  watch(token, (value) => {
    tokenCookie.value = value
  }, { immediate: true })

  const isAuthenticated = computed(() => Boolean(token.value))

  const clearSession = () => {
    token.value = null
    user.value = null
    tokenCookie.value = null
  }

  const login = async (credentials: { username: string, password: string }) => {
    const result = await authApi.login(credentials)

    if (!result.success || !result.token || !result.user) {
      clearSession()
      return result
    }

    token.value = result.token
    user.value = result.user

    return result
  }

  const fetchCurrentUser = async () => {
    if (!token.value) {
      return null
    }

    isLoadingUser.value = true

    try {
      const result = await authApi.me()

      if (!result.success || !result.user) {
        clearSession()
        return null
      }

      user.value = result.user

      return result.user
    } catch {
      clearSession()
      return null
    } finally {
      isLoadingUser.value = false
    }
  }

  const logout = () => {
    clearSession()
  }

  return {
    token,
    user,
    isAuthenticated,
    isLoadingUser,
    login,
    logout,
    fetchCurrentUser,
    clearSession
  }
}

export const useAuth = createSharedComposable(_useAuth)