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.
This commit is contained in:
padreug 2025-09-05 06:08:08 +02:00
parent e0443742c5
commit 7c439361b7
5 changed files with 298 additions and 133 deletions

View file

@ -0,0 +1,164 @@
import { ref, type Ref } from 'vue'
import { toast } from 'vue-sonner'
export interface AsyncOperationOptions {
successMessage?: string
errorMessage?: string
showToast?: boolean
showSuccessToast?: boolean
showErrorToast?: boolean
}
export interface AsyncOperationState<T> {
isLoading: Ref<boolean>
error: Ref<string | null>
data: Ref<T | null>
}
export interface AsyncOperationReturn<T> extends AsyncOperationState<T> {
execute: (operation: () => Promise<T>, options?: AsyncOperationOptions) => Promise<T | null>
reset: () => void
clear: () => void
}
/**
* Composable for standardized async operation handling
* Eliminates duplicate loading/error/success patterns across modules
*
* @example
* ```typescript
* const { isLoading, error, data, execute } = useAsyncOperation<OrderData>()
*
* const handleOrder = async () => {
* await execute(async () => {
* return await createOrder(orderData)
* }, {
* successMessage: 'Order created successfully!',
* errorMessage: 'Failed to create order'
* })
* }
* ```
*/
export function useAsyncOperation<T = any>(): AsyncOperationReturn<T> {
const isLoading = ref(false)
const error = ref<string | null>(null)
const data = ref(null) as Ref<T | null>
/**
* Execute an async operation with standardized error handling and loading states
*/
const execute = async (
operation: () => Promise<T>,
options: AsyncOperationOptions = {}
): Promise<T | null> => {
const {
successMessage,
errorMessage = 'Operation failed',
showToast = true,
showSuccessToast = showToast,
showErrorToast = showToast
} = options
try {
isLoading.value = true
error.value = null
const result = await operation()
data.value = result
// Show success toast if configured
if (showSuccessToast && successMessage) {
toast.success(successMessage)
}
return result
} catch (err) {
const errorMsg = err instanceof Error ? err.message : String(err)
error.value = errorMsg
// Show error toast if configured
if (showErrorToast) {
toast.error(errorMessage, {
description: errorMsg !== errorMessage ? errorMsg : undefined
})
}
// Re-throw to allow caller to handle if needed
throw err
} finally {
isLoading.value = false
}
}
/**
* Reset the operation state (clear error, keep data)
*/
const reset = (): void => {
isLoading.value = false
error.value = null
}
/**
* Clear all state (error, data, loading)
*/
const clear = (): void => {
isLoading.value = false
error.value = null
data.value = null
}
return {
// State
isLoading,
error,
data,
// Methods
execute,
reset,
clear
}
}
/**
* Specialized version for operations that don't return data
*/
export function useAsyncAction(): Omit<AsyncOperationReturn<void>, 'data'> {
const { data, ...rest } = useAsyncOperation<void>()
return rest
}
/**
* Multiple async operations manager
* Useful when you need to track multiple independent operations
*/
export function useMultiAsyncOperation<T extends Record<string, any>>() {
const operations = ref<Record<keyof T, AsyncOperationReturn<any>>>({} as any)
const createOperation = <K extends keyof T>(key: K): AsyncOperationReturn<T[K]> => {
if (!operations.value[key]) {
operations.value[key] = useAsyncOperation<T[K]>()
}
return operations.value[key] as AsyncOperationReturn<T[K]>
}
const isAnyLoading = (): boolean => {
return Object.values(operations.value).some((op: any) => op.isLoading.value)
}
const hasAnyError = (): boolean => {
return Object.values(operations.value).some((op: any) => op.error.value !== null)
}
const clearAll = (): void => {
Object.values(operations.value).forEach((op: any) => op.clear())
}
return {
operations,
createOperation,
isAnyLoading,
hasAnyError,
clearAll
}
}