webapp/src/composables/useAuth.ts
padreug 7c439361b7 Refactor authentication and async operation handling in useAuth composable
- Introduce useMultiAsyncOperation to manage multiple async operations in useAuth, enhancing error handling and loading state management.
- Replace manual loading and error state management with standardized async operation patterns for initialize, login, register, and logout functions.
- Update related components to utilize the new async operation structure, improving code clarity and maintainability.
- Add useAsyncOperation to other composables (useChat, useTicketPurchase, useMarket) for consistent async handling across the application.
2025-09-05 06:08:08 +02:00

168 lines
No EOL
4.5 KiB
TypeScript

import { ref, computed } from 'vue'
import { lnbitsAPI, type User, type LoginCredentials, type RegisterData } from '@/lib/api/lnbits'
import { useMultiAsyncOperation } from '@/core/composables/useAsyncOperation'
const currentUser = ref<User | null>(null)
// Shared async operations for auth actions
const authOperations = useMultiAsyncOperation<{
initialize: User | null
login: User
register: User
logout: void
}>()
export function useAuth() {
const isAuthenticated = computed(() => !!currentUser.value)
// Get operation instances
const initializeOp = authOperations.createOperation('initialize')
const loginOp = authOperations.createOperation('login')
const registerOp = authOperations.createOperation('register')
const logoutOp = authOperations.createOperation('logout')
/**
* Initialize authentication on app start
*/
async function initialize(): Promise<void> {
try {
await initializeOp.execute(async () => {
if (lnbitsAPI.isAuthenticated()) {
const user = await lnbitsAPI.getCurrentUser()
currentUser.value = user
return user
}
return null
}, {
errorMessage: 'Failed to initialize authentication',
showToast: false // Don't show toast for initialization errors
})
} catch {
// Clear invalid token on error
await logout()
}
}
/**
* Login with username and password
*/
async function login(credentials: LoginCredentials): Promise<void> {
await loginOp.execute(async () => {
await lnbitsAPI.login(credentials)
// Get user details
const user = await lnbitsAPI.getCurrentUser()
currentUser.value = user
return user
}, {
errorMessage: 'Login failed'
})
}
/**
* Register new user
*/
async function register(data: RegisterData): Promise<void> {
await registerOp.execute(async () => {
await lnbitsAPI.register(data)
// Get user details
const user = await lnbitsAPI.getCurrentUser()
currentUser.value = user
return user
}, {
errorMessage: 'Registration failed'
})
}
/**
* Logout and clear user data
*/
async function logout(): Promise<void> {
await logoutOp.execute(async () => {
// Clear local state
lnbitsAPI.logout()
currentUser.value = null
// Clear all auth operation states
authOperations.clearAll()
}, {
showToast: false // Don't show toast for logout
})
}
/**
* Update user password
*/
async function updatePassword(currentPassword: string, newPassword: string): Promise<void> {
const updatePasswordOp = authOperations.createOperation('updatePassword' as any)
return await updatePasswordOp.execute(async () => {
const updatedUser = await lnbitsAPI.updatePassword(currentPassword, newPassword)
currentUser.value = updatedUser
return updatedUser
}, {
errorMessage: 'Failed to update password'
})
}
/**
* Update user profile
*/
async function updateProfile(data: Partial<User>): Promise<void> {
const updateProfileOp = authOperations.createOperation('updateProfile' as any)
return await updateProfileOp.execute(async () => {
const updatedUser = await lnbitsAPI.updateProfile(data)
currentUser.value = updatedUser
return updatedUser
}, {
errorMessage: 'Failed to update profile'
})
}
/**
* Check if user is authenticated
*/
function checkAuth(): boolean {
return lnbitsAPI.isAuthenticated()
}
/**
* Get user display info
*/
const userDisplay = computed(() => {
if (!currentUser.value) return null
return {
name: currentUser.value.username || currentUser.value.email || 'Anonymous',
username: currentUser.value.username,
email: currentUser.value.email,
id: currentUser.value.id,
shortId: currentUser.value.id.slice(0, 8) + '...' + currentUser.value.id.slice(-8)
}
})
return {
// State
currentUser: computed(() => currentUser.value),
isAuthenticated,
isLoading: computed(() => authOperations.isAnyLoading()),
error: computed(() => authOperations.hasAnyError() ?
(initializeOp.error.value || loginOp.error.value || registerOp.error.value || logoutOp.error.value) : null),
userDisplay,
// Actions
initialize,
login,
register,
logout,
updatePassword,
updateProfile,
checkAuth
}
}
// Export singleton instance for global state
export const auth = useAuth()