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:
parent
e0443742c5
commit
7c439361b7
5 changed files with 298 additions and 133 deletions
|
|
@ -2,6 +2,7 @@ import { ref, computed } from 'vue'
|
|||
import { injectService } from '@/core/di-container'
|
||||
import type { ChatService } from '../services/chat-service'
|
||||
import type { ChatPeer } from '../types'
|
||||
import { useMultiAsyncOperation } from '@/core/composables/useAsyncOperation'
|
||||
|
||||
// Service token for chat service
|
||||
export const CHAT_SERVICE_TOKEN = Symbol('chatService')
|
||||
|
|
@ -14,8 +15,15 @@ export function useChat() {
|
|||
}
|
||||
|
||||
const selectedPeer = ref<string | null>(null)
|
||||
const isLoading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
// Async operations
|
||||
const asyncOps = useMultiAsyncOperation<{
|
||||
sendMessage: void
|
||||
refreshPeers: void
|
||||
}>()
|
||||
|
||||
const sendMessageOp = asyncOps.createOperation('sendMessage')
|
||||
const refreshPeersOp = asyncOps.createOperation('refreshPeers')
|
||||
|
||||
// Computed properties
|
||||
const peers = computed(() => chatService.allPeers.value)
|
||||
|
|
@ -41,17 +49,11 @@ export function useChat() {
|
|||
return
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
await chatService.sendMessage(selectedPeer.value, content.trim())
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : 'Failed to send message'
|
||||
console.error('Send message error:', err)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
return await sendMessageOp.execute(async () => {
|
||||
await chatService.sendMessage(selectedPeer.value!, content.trim())
|
||||
}, {
|
||||
errorMessage: 'Failed to send message'
|
||||
})
|
||||
}
|
||||
|
||||
const addPeer = (pubkey: string, name?: string): ChatPeer => {
|
||||
|
|
@ -63,23 +65,22 @@ export function useChat() {
|
|||
}
|
||||
|
||||
const refreshPeers = async () => {
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
return await refreshPeersOp.execute(async () => {
|
||||
await chatService.refreshPeers()
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : 'Failed to refresh peers'
|
||||
console.error('Failed to refresh peers:', err)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}, {
|
||||
errorMessage: 'Failed to refresh peers'
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
selectedPeer,
|
||||
isLoading,
|
||||
error,
|
||||
isSendingMessage: sendMessageOp.isLoading,
|
||||
sendMessageError: sendMessageOp.error,
|
||||
isRefreshingPeers: refreshPeersOp.isLoading,
|
||||
refreshPeersError: refreshPeersOp.error,
|
||||
isLoading: computed(() => asyncOps.isAnyLoading()),
|
||||
error: computed(() => sendMessageOp.error.value || refreshPeersOp.error.value),
|
||||
|
||||
// Computed
|
||||
peers,
|
||||
|
|
|
|||
|
|
@ -2,13 +2,15 @@ import { ref, computed, onUnmounted } from 'vue'
|
|||
import { purchaseTicket, checkPaymentStatus, payInvoiceWithWallet } from '@/lib/api/events'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { useAsyncOperation } from '@/core/composables/useAsyncOperation'
|
||||
|
||||
export function useTicketPurchase() {
|
||||
const { isAuthenticated, currentUser } = useAuth()
|
||||
|
||||
// Async operations
|
||||
const purchaseOperation = useAsyncOperation()
|
||||
|
||||
// State
|
||||
const isLoading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
const paymentHash = ref<string | null>(null)
|
||||
const paymentRequest = ref<string | null>(null)
|
||||
const qrCode = ref<string | null>(null)
|
||||
|
|
@ -50,7 +52,7 @@ export function useTicketPurchase() {
|
|||
qrCode.value = dataUrl
|
||||
} catch (err) {
|
||||
console.error('Error generating QR code:', err)
|
||||
error.value = 'Failed to generate QR code'
|
||||
// Note: error handling is now managed by the purchaseOperation
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,16 +100,15 @@ export function useTicketPurchase() {
|
|||
throw new Error('User must be authenticated to purchase tickets')
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
paymentHash.value = null
|
||||
paymentRequest.value = null
|
||||
qrCode.value = null
|
||||
ticketQRCode.value = null
|
||||
purchasedTicketId.value = null
|
||||
showTicketQR.value = false
|
||||
return await purchaseOperation.execute(async () => {
|
||||
// Clear previous state
|
||||
paymentHash.value = null
|
||||
paymentRequest.value = null
|
||||
qrCode.value = null
|
||||
ticketQRCode.value = null
|
||||
purchasedTicketId.value = null
|
||||
showTicketQR.value = false
|
||||
|
||||
try {
|
||||
// Get the invoice
|
||||
const invoice = await purchaseTicket(eventId)
|
||||
paymentHash.value = invoice.payment_hash
|
||||
|
|
@ -133,12 +134,11 @@ export function useTicketPurchase() {
|
|||
// No wallet balance, proceed with manual payment
|
||||
await startPaymentStatusCheck(eventId, invoice.payment_hash)
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : 'Failed to purchase ticket'
|
||||
console.error('Error purchasing ticket:', err)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
return invoice
|
||||
}, {
|
||||
errorMessage: 'Failed to purchase ticket'
|
||||
})
|
||||
}
|
||||
|
||||
// Start payment status check
|
||||
|
|
@ -184,8 +184,7 @@ export function useTicketPurchase() {
|
|||
|
||||
// Reset payment state
|
||||
function resetPaymentState() {
|
||||
isLoading.value = false
|
||||
error.value = null
|
||||
purchaseOperation.clear()
|
||||
paymentHash.value = null
|
||||
paymentRequest.value = null
|
||||
qrCode.value = null
|
||||
|
|
@ -215,8 +214,8 @@ export function useTicketPurchase() {
|
|||
|
||||
return {
|
||||
// State
|
||||
isLoading,
|
||||
error,
|
||||
isLoading: purchaseOperation.isLoading,
|
||||
error: purchaseOperation.error,
|
||||
paymentHash,
|
||||
paymentRequest,
|
||||
qrCode,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { injectService, SERVICE_TOKENS } from '@/core/di-container'
|
|||
import { config } from '@/lib/config'
|
||||
import { nostrmarketService } from '../services/nostrmarketService'
|
||||
import { nip04 } from 'nostr-tools'
|
||||
import { useAsyncOperation } from '@/core/composables/useAsyncOperation'
|
||||
|
||||
// Nostr event kinds for market functionality
|
||||
const MARKET_EVENT_KINDS = {
|
||||
|
|
@ -44,9 +45,11 @@ export function useMarket() {
|
|||
}
|
||||
}
|
||||
|
||||
// Async operations
|
||||
const marketOperation = useAsyncOperation()
|
||||
const connectionOperation = useAsyncOperation()
|
||||
|
||||
// State
|
||||
const isLoading = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
const isConnected = ref(false)
|
||||
const activeMarket = computed(() => marketStore.activeMarket)
|
||||
const markets = computed(() => marketStore.markets)
|
||||
|
|
@ -56,20 +59,15 @@ export function useMarket() {
|
|||
|
||||
// Connection state
|
||||
const connectionStatus = computed(() => {
|
||||
if (connectionOperation.isLoading.value) return 'connecting'
|
||||
if (isConnected.value) return 'connected'
|
||||
if (nostrStore.isConnecting) return 'connecting'
|
||||
if (nostrStore.error) return 'error'
|
||||
if (connectionOperation.error.value || nostrStore.error) return 'error'
|
||||
return 'disconnected'
|
||||
})
|
||||
|
||||
// Load market from naddr
|
||||
const loadMarket = async (naddr: string) => {
|
||||
try {
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
// Load market from naddr
|
||||
|
||||
return await marketOperation.execute(async () => {
|
||||
// Parse naddr to get market data
|
||||
// TODO: Confirm if this should use nostrStore.account?.pubkey or authService.user.value?.pubkey
|
||||
const marketData = {
|
||||
|
|
@ -82,13 +80,10 @@ export function useMarket() {
|
|||
}
|
||||
|
||||
await loadMarketData(marketData)
|
||||
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err : new Error('Failed to load market')
|
||||
throw err
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
return marketData
|
||||
}, {
|
||||
errorMessage: 'Failed to load market'
|
||||
})
|
||||
}
|
||||
|
||||
// Load market data from Nostr events
|
||||
|
|
@ -560,7 +555,7 @@ export function useMarket() {
|
|||
|
||||
// Connect to market
|
||||
const connectToMarket = async () => {
|
||||
try {
|
||||
return await connectionOperation.execute(async () => {
|
||||
console.log('🛒 Checking RelayHub connection...')
|
||||
// Use existing relay hub connection (should already be connected by base module)
|
||||
isConnected.value = relayHub.isConnected.value
|
||||
|
|
@ -602,18 +597,18 @@ export function useMarket() {
|
|||
|
||||
// Note: Order-related DMs are now handled by chat service forwarding
|
||||
// No need for separate subscription
|
||||
|
||||
} catch (err) {
|
||||
console.error('🛒 Failed to connect to market:', err)
|
||||
error.value = err instanceof Error ? err : new Error('Failed to connect to market')
|
||||
throw err
|
||||
}
|
||||
|
||||
return { isConnected: isConnected.value }
|
||||
}, {
|
||||
errorMessage: 'Failed to connect to market'
|
||||
})
|
||||
}
|
||||
|
||||
// Disconnect from market
|
||||
const disconnectFromMarket = () => {
|
||||
isConnected.value = false
|
||||
error.value = null
|
||||
marketOperation.clear()
|
||||
connectionOperation.clear()
|
||||
// Market disconnected
|
||||
}
|
||||
|
||||
|
|
@ -631,8 +626,10 @@ export function useMarket() {
|
|||
|
||||
return {
|
||||
// State
|
||||
isLoading: readonly(isLoading),
|
||||
error: readonly(error),
|
||||
isLoading: readonly(marketOperation.isLoading),
|
||||
error: readonly(marketOperation.error),
|
||||
isConnecting: readonly(connectionOperation.isLoading),
|
||||
connectionError: readonly(connectionOperation.error),
|
||||
isConnected: readonly(isConnected),
|
||||
connectionStatus: readonly(connectionStatus),
|
||||
activeMarket: readonly(activeMarket),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue