Files
vigilcare-records/vigilcare-records-web/src/stores/auth.ts
T

121 lines
3.5 KiB
TypeScript

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { post, get } from '../api/client'
import type { User, LoginRequest, LoginResponse, UserProfileResponse } from '../types'
import router from '../router'
export function getDefaultRouteForRole(role: string): string {
switch (role) {
case 'INTAKE_CLERK':
return '/intake'
case 'DATA_ENTRY_CLERK':
return '/entry'
case 'VERIFIER':
case 'CLINICAL_APPROVER':
return '/verification'
case 'ADMINISTRATOR':
return '/dashboard'
default:
return '/login'
}
}
export const useAuthStore = defineStore('auth', () => {
const token = ref<string | null>(localStorage.getItem('vigilcare_token'))
const refreshToken = ref<string | null>(localStorage.getItem('vigilcare_refresh_token'))
const user = ref<User | null>(
JSON.parse(localStorage.getItem('vigilcare_user') || 'null')
)
const isAuthenticated = computed(() => !!token.value)
const userRole = computed(() => user.value?.role ?? '')
const userId = computed(() => user.value?.id ?? '')
const userFullName = computed(() => user.value?.fullName ?? '')
// Role-based view access
const canIntake = computed(() =>
['INTAKE_CLERK', 'ADMINISTRATOR'].includes(userRole.value)
)
const canEntry = computed(() =>
['DATA_ENTRY_CLERK', 'ADMINISTRATOR'].includes(userRole.value)
)
const canVerify = computed(() =>
['VERIFIER', 'CLINICAL_APPROVER', 'ADMINISTRATOR'].includes(userRole.value)
)
const canSupervise = computed(() =>
['ADMINISTRATOR'].includes(userRole.value)
)
async function login(credentials: LoginRequest): Promise<void> {
const response = await post<LoginResponse>('auth/login', credentials)
if (!response.success || !response.data) {
throw new Error(response.error?.message ?? 'Login failed')
}
const loginData = response.data
token.value = loginData.token
refreshToken.value = loginData.refreshToken
user.value = {
id: loginData.userId,
username: loginData.username,
fullName: loginData.fullName,
role: loginData.role,
}
localStorage.setItem('vigilcare_token', loginData.token)
localStorage.setItem('vigilcare_refresh_token', loginData.refreshToken)
localStorage.setItem('vigilcare_user', JSON.stringify(user.value))
router.push(getDefaultRouteForRole(loginData.role))
}
async function fetchCurrentUser(): Promise<void> {
const response = await get<UserProfileResponse>('auth/me')
if (response.success && response.data) {
user.value = {
id: response.data.id,
username: response.data.username,
fullName: response.data.fullName,
role: response.data.role,
}
localStorage.setItem('vigilcare_user', JSON.stringify(user.value))
}
}
async function logout(): Promise<void> {
if (refreshToken.value) {
try {
await post<void>('auth/logout', { refreshToken: refreshToken.value })
} catch {
// Still clear local session if server revoke fails
}
}
token.value = null
refreshToken.value = null
user.value = null
localStorage.removeItem('vigilcare_token')
localStorage.removeItem('vigilcare_refresh_token')
localStorage.removeItem('vigilcare_user')
router.push('/login')
}
return {
token,
refreshToken,
user,
isAuthenticated,
userRole,
userId,
userFullName,
canIntake,
canEntry,
canVerify,
canSupervise,
login,
fetchCurrentUser,
logout,
}
})