Files

95 lines
2.1 KiB
TypeScript

import { computed, ref } from 'vue'
import { defineStore } from 'pinia'
import { getCurrentUserApi, loginApi } from '../services/auth'
import { hasAnyPermission, hasPermission } from '../services/access'
import type { CurrentUser } from '../types/auth'
const TOKEN_KEY = 'teapot-system-token'
const USER_KEY = 'teapot-system-user'
function readUserFromStorage() {
const raw = window.localStorage.getItem(USER_KEY)
if (!raw) {
return null
}
try {
return JSON.parse(raw) as CurrentUser
} catch {
return null
}
}
export const useAuthStore = defineStore('auth', () => {
const token = ref(window.localStorage.getItem(TOKEN_KEY) ?? '')
const user = ref<CurrentUser | null>(readUserFromStorage())
const initialized = ref(false)
const isAuthenticated = computed(() => Boolean(token.value && user.value))
function persistSession() {
if (token.value) {
window.localStorage.setItem(TOKEN_KEY, token.value)
} else {
window.localStorage.removeItem(TOKEN_KEY)
}
if (user.value) {
window.localStorage.setItem(USER_KEY, JSON.stringify(user.value))
} else {
window.localStorage.removeItem(USER_KEY)
}
}
async function login(username: string, password: string) {
const payload = await loginApi({ username, password })
token.value = payload.token
user.value = payload.user
initialized.value = true
persistSession()
}
async function bootstrap() {
if (!token.value) {
initialized.value = true
return
}
try {
user.value = await getCurrentUserApi(token.value)
} catch {
token.value = ''
user.value = null
persistSession()
} finally {
initialized.value = true
}
}
function logout() {
token.value = ''
user.value = null
initialized.value = true
persistSession()
}
function can(permission: string) {
return hasPermission(user.value, permission)
}
function canAny(permissions: string[]) {
return hasAnyPermission(user.value, permissions)
}
return {
token,
user,
initialized,
isAuthenticated,
login,
bootstrap,
logout,
can,
canAny,
}
})