Squash merge remove-dangling-bits into market-implementation-squashed
This commit is contained in:
parent
4bc15cfa2f
commit
2f0024478d
17 changed files with 569 additions and 859 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { ref, computed, onMounted, onUnmounted, readonly } from 'vue'
|
||||
import { ref, computed, onUnmounted, readonly } from 'vue'
|
||||
import { nostrclientHub, type SubscriptionConfig } from '../lib/nostr/nostrclientHub'
|
||||
|
||||
export function useNostrclientHub() {
|
||||
|
|
|
|||
|
|
@ -1,47 +1,84 @@
|
|||
import { ref, computed, watch } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
import { nip04 } from 'nostr-tools'
|
||||
import { relayHubComposable } from './useRelayHub'
|
||||
import { useAuth } from './useAuth'
|
||||
import { useMarketStore } from '@/stores/market'
|
||||
import { config } from '@/lib/config'
|
||||
import type { Order, OrderStatus } from '@/stores/market'
|
||||
import type { LightningInvoice } from '@/lib/services/invoiceService'
|
||||
import { decode } from 'light-bolt11-decoder'
|
||||
|
||||
// Order event types based on NIP-69 and nostrmarket patterns
|
||||
export enum OrderEventType {
|
||||
CUSTOMER_ORDER = 'customer_order',
|
||||
PAYMENT_REQUEST = 'payment_request',
|
||||
ORDER_PAID = 'order_paid',
|
||||
ORDER_SHIPPED = 'order_shipped',
|
||||
ORDER_DELIVERED = 'order_delivered',
|
||||
ORDER_CANCELLED = 'order_cancelled',
|
||||
INVOICE_GENERATED = 'invoice_generated'
|
||||
// Nostrmarket Order interfaces based on the actual implementation
|
||||
|
||||
// Nostrmarket Order interfaces based on the actual implementation
|
||||
interface OrderItem {
|
||||
product_id: string
|
||||
quantity: number
|
||||
}
|
||||
|
||||
export interface OrderEvent {
|
||||
type: OrderEventType
|
||||
orderId: string
|
||||
data: any
|
||||
timestamp: number
|
||||
senderPubkey: string
|
||||
interface OrderContact {
|
||||
nostr?: string
|
||||
phone?: string
|
||||
email?: string
|
||||
}
|
||||
|
||||
export interface PaymentRequestEvent {
|
||||
type: OrderEventType.PAYMENT_REQUEST
|
||||
orderId: string
|
||||
paymentRequest: string
|
||||
amount: number
|
||||
currency: string
|
||||
memo: string
|
||||
expiresAt: number
|
||||
// Direct message types from nostrmarket
|
||||
enum DirectMessageType {
|
||||
PLAIN_TEXT = -1,
|
||||
CUSTOMER_ORDER = 0,
|
||||
PAYMENT_REQUEST = 1,
|
||||
ORDER_PAID_OR_SHIPPED = 2
|
||||
}
|
||||
|
||||
export interface OrderStatusEvent {
|
||||
type: OrderEventType.ORDER_PAID | OrderEventType.ORDER_SHIPPED | OrderEventType.ORDER_DELIVERED
|
||||
orderId: string
|
||||
status: OrderStatus
|
||||
timestamp: number
|
||||
additionalData?: any
|
||||
// Event types for nostrmarket protocol
|
||||
interface CustomerOrderEvent {
|
||||
type: DirectMessageType.CUSTOMER_ORDER
|
||||
id: string
|
||||
items: OrderItem[]
|
||||
contact?: OrderContact
|
||||
shipping_id: string
|
||||
message?: string
|
||||
}
|
||||
|
||||
interface PaymentRequestEvent {
|
||||
type: DirectMessageType.PAYMENT_REQUEST
|
||||
id: string
|
||||
message?: string
|
||||
payment_options: Array<{
|
||||
type: string
|
||||
link: string
|
||||
}>
|
||||
}
|
||||
|
||||
interface OrderStatusEvent {
|
||||
type: DirectMessageType.ORDER_PAID_OR_SHIPPED
|
||||
id: string
|
||||
message?: string
|
||||
paid?: boolean
|
||||
shipped?: boolean
|
||||
}
|
||||
|
||||
// Helper function to extract expiry from bolt11 invoice
|
||||
function extractExpiryFromBolt11(bolt11String: string): string | undefined {
|
||||
try {
|
||||
const decoded = decode(bolt11String)
|
||||
console.log('Decoded bolt11 invoice:', {
|
||||
amount: decoded.sections.find(section => section.name === 'amount')?.value,
|
||||
expiry: decoded.expiry,
|
||||
timestamp: decoded.sections.find(section => section.name === 'timestamp')?.value
|
||||
})
|
||||
|
||||
// Calculate expiry date from timestamp + expiry seconds
|
||||
const timestamp = decoded.sections.find(section => section.name === 'timestamp')?.value as number
|
||||
const expirySeconds = decoded.expiry as number
|
||||
|
||||
if (timestamp && expirySeconds) {
|
||||
const expiryDate = new Date((timestamp + expirySeconds) * 1000)
|
||||
return expiryDate.toISOString()
|
||||
}
|
||||
|
||||
return undefined
|
||||
} catch (error) {
|
||||
console.warn('Failed to extract expiry from bolt11:', error)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
export function useOrderEvents() {
|
||||
|
|
@ -62,524 +99,216 @@ export function useOrderEvents() {
|
|||
const isConnected = relayHub.isConnected.value
|
||||
const hasPubkey = !!currentUserPubkey.value
|
||||
|
||||
console.log('OrderEvents isReady check:', { isAuth, isConnected, hasPubkey })
|
||||
return isAuth && isConnected && hasPubkey
|
||||
})
|
||||
|
||||
// Subscribe to order events
|
||||
const subscribeToOrderEvents = async () => {
|
||||
console.log('subscribeToOrderEvents called with:', {
|
||||
isReady: isReady.value,
|
||||
isSubscribed: isSubscribed.value,
|
||||
currentUserPubkey: currentUserPubkey.value,
|
||||
relayHubConnected: relayHub.isConnected.value,
|
||||
authStatus: auth.isAuthenticated
|
||||
})
|
||||
|
||||
if (!isReady.value || isSubscribed.value) {
|
||||
console.warn('Cannot subscribe to order events: not ready or already subscribed', {
|
||||
isReady: isReady.value,
|
||||
isSubscribed: isSubscribed.value
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('Subscribing to order events for user:', currentUserPubkey.value)
|
||||
|
||||
// Subscribe to direct messages (kind 4) that contain order information
|
||||
const filters = [
|
||||
{
|
||||
kinds: [4], // NIP-04 encrypted direct messages
|
||||
'#p': [currentUserPubkey.value].filter(Boolean) as string[], // Messages to us, filter out undefined
|
||||
'#p': [currentUserPubkey.value].filter(Boolean) as string[],
|
||||
since: lastEventTimestamp.value
|
||||
}
|
||||
]
|
||||
|
||||
console.log('Using filters:', filters)
|
||||
|
||||
const unsubscribe = relayHub.subscribe({
|
||||
id: `order-events-${currentUserPubkey.value}-${Date.now()}`,
|
||||
relayHub.subscribe({
|
||||
id: 'order-events',
|
||||
filters,
|
||||
relays: config.market.supportedRelays,
|
||||
onEvent: (event: any) => {
|
||||
console.log('Received event in order subscription:', event.id)
|
||||
handleOrderEvent(event)
|
||||
},
|
||||
onEvent: handleOrderEvent,
|
||||
onEose: () => {
|
||||
console.log('Order events subscription EOSE')
|
||||
console.log('Order events subscription ended')
|
||||
}
|
||||
})
|
||||
|
||||
subscriptionId.value = `order-events-${currentUserPubkey.value}-${Date.now()}`
|
||||
subscriptionId.value = 'order-events'
|
||||
isSubscribed.value = true
|
||||
console.log('Successfully subscribed to order events')
|
||||
|
||||
console.log('Successfully subscribed to order events with ID:', subscriptionId.value)
|
||||
return unsubscribe
|
||||
} catch (error) {
|
||||
console.error('Failed to subscribe to order events:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Handle incoming order events
|
||||
const handleOrderEvent = async (event: any) => {
|
||||
if (!auth.currentUser?.value?.prvkey) {
|
||||
console.warn('Cannot decrypt order event: no private key available')
|
||||
return
|
||||
}
|
||||
|
||||
// Check if we've already processed this event
|
||||
if (processedEventIds.value.has(event.id)) {
|
||||
return
|
||||
}
|
||||
|
||||
processedEventIds.value.add(event.id)
|
||||
lastEventTimestamp.value = Math.max(lastEventTimestamp.value, event.created_at)
|
||||
|
||||
try {
|
||||
// Decrypt the message content
|
||||
const decryptedContent = await nip04.decrypt(
|
||||
auth.currentUser.value.prvkey,
|
||||
event.pubkey, // Sender's pubkey
|
||||
auth.currentUser.value?.prvkey || '',
|
||||
event.pubkey,
|
||||
event.content
|
||||
)
|
||||
|
||||
// Parse the decrypted content
|
||||
const orderEvent = JSON.parse(decryptedContent)
|
||||
// Parse the JSON content
|
||||
const jsonData = JSON.parse(decryptedContent)
|
||||
|
||||
console.log('Received order event:', {
|
||||
eventId: event.id,
|
||||
type: orderEvent.type,
|
||||
orderId: orderEvent.orderId,
|
||||
sender: event.pubkey
|
||||
})
|
||||
|
||||
// Handle nostrmarket protocol messages
|
||||
if (orderEvent.type === 0 || orderEvent.type === 1 || orderEvent.type === 2) {
|
||||
await handleNostrmarketMessage(orderEvent, event.pubkey)
|
||||
return
|
||||
}
|
||||
|
||||
// Process the order event based on type
|
||||
await processOrderEvent(orderEvent, event.pubkey)
|
||||
|
||||
// Mark as processed
|
||||
processedEventIds.value.add(event.id)
|
||||
lastEventTimestamp.value = Math.max(lastEventTimestamp.value, event.created_at)
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to process order event:', {
|
||||
eventId: event.id,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Handle nostrmarket protocol messages (type 0, 1, 2)
|
||||
const handleNostrmarketMessage = async (message: any, senderPubkey: string) => {
|
||||
try {
|
||||
console.log('Processing nostrmarket message:', {
|
||||
type: message.type,
|
||||
orderId: message.id,
|
||||
sender: senderPubkey
|
||||
})
|
||||
|
||||
// Import nostrmarket service
|
||||
const { nostrmarketService } = await import('@/lib/services/nostrmarketService')
|
||||
|
||||
switch (message.type) {
|
||||
case 0:
|
||||
// Customer order - this should be handled by the merchant side
|
||||
console.log('Received customer order (type 0) - this should be handled by merchant')
|
||||
// Handle different message types
|
||||
switch (jsonData.type) {
|
||||
case DirectMessageType.CUSTOMER_ORDER:
|
||||
await handleCustomerOrder(jsonData as CustomerOrderEvent, event.pubkey)
|
||||
break
|
||||
|
||||
case 1:
|
||||
// Payment request from merchant
|
||||
console.log('Received payment request from merchant')
|
||||
await nostrmarketService.handlePaymentRequest(message)
|
||||
case DirectMessageType.PAYMENT_REQUEST:
|
||||
await handlePaymentRequest(jsonData as PaymentRequestEvent, event.pubkey)
|
||||
break
|
||||
|
||||
case 2:
|
||||
// Order status update from merchant
|
||||
console.log('Received order status update from merchant')
|
||||
await nostrmarketService.handleOrderStatusUpdate(message)
|
||||
case DirectMessageType.ORDER_PAID_OR_SHIPPED:
|
||||
await handleOrderStatusUpdate(jsonData as OrderStatusEvent, event.pubkey)
|
||||
break
|
||||
|
||||
default:
|
||||
console.warn('Unknown nostrmarket message type:', message.type)
|
||||
console.log('Unknown message type:', jsonData.type)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to handle nostrmarket message:', error)
|
||||
console.error('Error processing order event:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Process incoming Nostr events
|
||||
const processOrderEvent = async (event: any, senderPubkey: string) => {
|
||||
try {
|
||||
console.log('Received order event:', {
|
||||
eventId: event.id || 'unknown',
|
||||
type: event.type,
|
||||
orderId: event.orderId,
|
||||
sender: senderPubkey
|
||||
})
|
||||
// Handle customer order (type 0)
|
||||
const handleCustomerOrder = async (orderData: CustomerOrderEvent, _senderPubkey: string) => {
|
||||
console.log('Received customer order:', orderData)
|
||||
|
||||
// Only process events that have the required market order structure
|
||||
if (!event.type || event.type !== 'market_order') {
|
||||
console.log('Skipping non-market order event:', event.type)
|
||||
return
|
||||
}
|
||||
// Create a basic order object from the event data
|
||||
const order = {
|
||||
id: orderData.id,
|
||||
type: DirectMessageType.CUSTOMER_ORDER,
|
||||
items: orderData.items,
|
||||
contact: orderData.contact,
|
||||
shipping_id: orderData.shipping_id,
|
||||
message: orderData.message,
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now()
|
||||
}
|
||||
|
||||
// Validate that this is actually a market order event
|
||||
if (!event.orderId || !event.items || !Array.isArray(event.items)) {
|
||||
console.log('Skipping invalid market order event - missing required fields')
|
||||
return
|
||||
}
|
||||
// Store the order in our local state
|
||||
// Note: We're not using the complex Order interface from market store
|
||||
// Instead, we're using the simple nostrmarket format
|
||||
console.log('Processed customer order:', order)
|
||||
}
|
||||
|
||||
console.log('Processing market order:', event)
|
||||
|
||||
// Check if this order already exists - use the orderId as the primary key
|
||||
const existingOrder = Object.values(marketStore.orders).find(
|
||||
order => order.id === event.orderId
|
||||
)
|
||||
// Handle payment request (type 1)
|
||||
const handlePaymentRequest = async (paymentData: PaymentRequestEvent, _senderPubkey: string) => {
|
||||
console.log('Received payment request:', paymentData)
|
||||
|
||||
// Find the lightning payment option
|
||||
const lightningOption = paymentData.payment_options?.find(opt => opt.type === 'ln')
|
||||
if (lightningOption) {
|
||||
console.log('Lightning payment request:', lightningOption.link)
|
||||
|
||||
// Find the existing order by ID
|
||||
const existingOrder = marketStore.orders[paymentData.id]
|
||||
if (existingOrder) {
|
||||
console.log('Order already exists, updating with new information:', existingOrder.id)
|
||||
console.log('Found existing order, updating with payment request:', existingOrder.id)
|
||||
|
||||
// Update the existing order with any new information
|
||||
const updatedOrder = {
|
||||
...existingOrder,
|
||||
updatedAt: Math.floor(Date.now() / 1000)
|
||||
// Try to extract actual expiry from bolt11
|
||||
const actualExpiry = extractExpiryFromBolt11(lightningOption.link)
|
||||
|
||||
// Create lightning invoice object
|
||||
const lightningInvoice = {
|
||||
checking_id: '', // Will be extracted from bolt11 if needed
|
||||
payment_hash: '', // Will be extracted from bolt11 if needed
|
||||
wallet_id: '', // Not available from payment request
|
||||
amount: existingOrder.total,
|
||||
fee: 0, // Not available from payment request
|
||||
bolt11: lightningOption.link,
|
||||
status: 'pending',
|
||||
memo: paymentData.message || 'Payment for order',
|
||||
created_at: new Date().toISOString(),
|
||||
expiry: actualExpiry // Use actual expiry from bolt11 decoding
|
||||
}
|
||||
|
||||
// If there's invoice information, update it
|
||||
if (event.lightningInvoice) {
|
||||
updatedOrder.lightningInvoice = event.lightningInvoice
|
||||
updatedOrder.paymentHash = event.paymentHash
|
||||
updatedOrder.paymentStatus = event.paymentStatus || 'pending'
|
||||
updatedOrder.paymentRequest = event.paymentRequest
|
||||
}
|
||||
|
||||
// Update the order in the store
|
||||
marketStore.updateOrder(existingOrder.id, updatedOrder)
|
||||
|
||||
console.log('Updated existing order:', {
|
||||
orderId: existingOrder.id,
|
||||
hasInvoice: !!updatedOrder.lightningInvoice,
|
||||
paymentStatus: updatedOrder.paymentStatus
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Create a basic order object from the event data
|
||||
const orderData: Partial<Order> = {
|
||||
id: event.orderId,
|
||||
nostrEventId: event.id || 'unknown',
|
||||
buyerPubkey: senderPubkey,
|
||||
sellerPubkey: event.sellerPubkey || '',
|
||||
items: event.items || [],
|
||||
total: event.total || 0,
|
||||
currency: event.currency || 'sat',
|
||||
status: 'pending' as OrderStatus,
|
||||
createdAt: event.createdAt || Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
// Add invoice details if present
|
||||
...(event.lightningInvoice && {
|
||||
lightningInvoice: {
|
||||
checking_id: event.lightningInvoice.checking_id || event.lightningInvoice.payment_hash || '',
|
||||
payment_hash: event.lightningInvoice.payment_hash || '',
|
||||
wallet_id: event.lightningInvoice.wallet_id || '',
|
||||
amount: event.lightningInvoice.amount || 0,
|
||||
fee: event.lightningInvoice.fee || 0,
|
||||
bolt11: event.lightningInvoice.bolt11 || event.lightningInvoice.payment_request || '',
|
||||
status: 'pending',
|
||||
memo: event.lightningInvoice.memo || '',
|
||||
expiry: event.lightningInvoice.expiry || '',
|
||||
preimage: event.lightningInvoice.preimage || '',
|
||||
extra: event.lightningInvoice.extra || {},
|
||||
created_at: event.lightningInvoice.created_at || '',
|
||||
updated_at: event.lightningInvoice.updated_at || ''
|
||||
},
|
||||
paymentHash: event.lightningInvoice.payment_hash || '',
|
||||
paymentStatus: 'pending',
|
||||
paymentRequest: event.lightningInvoice.bolt11 || event.lightningInvoice.payment_request || '',
|
||||
// Update the order with the lightning invoice
|
||||
marketStore.updateOrder(existingOrder.id, {
|
||||
lightningInvoice,
|
||||
status: 'pending',
|
||||
paymentRequest: lightningOption.link,
|
||||
updatedAt: Date.now()
|
||||
})
|
||||
}
|
||||
|
||||
// Create the order using the store method
|
||||
const order = marketStore.createOrder({
|
||||
id: event.id,
|
||||
cartId: event.id,
|
||||
stallId: 'unknown', // We'll need to determine this from the items
|
||||
buyerPubkey: senderPubkey,
|
||||
sellerPubkey: '', // Will be set when we know the merchant
|
||||
status: 'pending',
|
||||
items: Array.from(orderData.items || []), // Convert readonly to mutable
|
||||
contactInfo: orderData.contactInfo || {},
|
||||
shippingZone: orderData.shippingZone || {
|
||||
id: 'online',
|
||||
name: 'Online',
|
||||
cost: 0,
|
||||
currency: 'sat',
|
||||
description: 'Online delivery'
|
||||
},
|
||||
paymentMethod: 'lightning',
|
||||
subtotal: 0,
|
||||
shippingCost: 0,
|
||||
total: 0,
|
||||
currency: 'sat',
|
||||
originalOrderId: event.id
|
||||
})
|
||||
|
||||
console.log('Created order from market event:', {
|
||||
orderId: order.id,
|
||||
total: order.total,
|
||||
status: order.status
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to handle market order:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle payment request events
|
||||
const handlePaymentRequest = async (event: PaymentRequestEvent, _senderPubkey: string) => {
|
||||
try {
|
||||
// Find the order in our store
|
||||
const order = marketStore.orders[event.orderId]
|
||||
if (!order) {
|
||||
console.warn('Payment request received for unknown order:', event.orderId)
|
||||
return
|
||||
}
|
||||
|
||||
// Update order with payment request (excluding readonly items)
|
||||
const { items, ...orderWithoutItems } = order
|
||||
const updatedOrder = {
|
||||
...orderWithoutItems,
|
||||
paymentRequest: event.paymentRequest,
|
||||
paymentStatus: 'pending' as const,
|
||||
updatedAt: Date.now() / 1000
|
||||
}
|
||||
|
||||
// Update the order in the store
|
||||
marketStore.updateOrder(event.orderId, updatedOrder)
|
||||
|
||||
console.log('Order updated with payment request:', {
|
||||
orderId: event.orderId,
|
||||
amount: event.amount,
|
||||
currency: event.currency
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to handle payment request:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle order status updates
|
||||
const handleOrderStatusUpdate = async (event: OrderStatusEvent, _senderPubkey: string) => {
|
||||
try {
|
||||
// Find the order in our store
|
||||
const order = marketStore.orders[event.orderId]
|
||||
if (!order) {
|
||||
console.warn('Status update received for unknown order:', event.orderId)
|
||||
return
|
||||
}
|
||||
|
||||
// Update order status
|
||||
marketStore.updateOrderStatus(event.orderId, event.status)
|
||||
|
||||
console.log('Order status updated:', {
|
||||
orderId: event.orderId,
|
||||
newStatus: event.status,
|
||||
timestamp: event.timestamp
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to handle order status update:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle invoice generation events
|
||||
const handleInvoiceGenerated = async (event: any, _senderPubkey: string) => {
|
||||
try {
|
||||
// Find the order in our store
|
||||
const order = marketStore.orders[event.orderId]
|
||||
if (!order) {
|
||||
console.warn('Invoice generated for unknown order:', event.orderId)
|
||||
return
|
||||
}
|
||||
|
||||
// Update order with invoice details (excluding readonly items)
|
||||
const { items, ...orderWithoutItems } = order
|
||||
const updatedOrder = {
|
||||
...orderWithoutItems,
|
||||
lightningInvoice: {
|
||||
payment_hash: event.paymentHash,
|
||||
payment_request: event.paymentRequest,
|
||||
amount: event.amount,
|
||||
memo: event.memo,
|
||||
expiry: event.expiresAt,
|
||||
created_at: event.timestamp,
|
||||
status: 'pending' as const
|
||||
},
|
||||
paymentHash: event.paymentHash,
|
||||
paymentStatus: 'pending' as const,
|
||||
updatedAt: Date.now() / 1000
|
||||
}
|
||||
|
||||
// Update the order in the store
|
||||
marketStore.updateOrder(event.orderId, updatedOrder)
|
||||
|
||||
console.log('Order updated with invoice details:', {
|
||||
orderId: event.orderId,
|
||||
paymentHash: event.paymentHash,
|
||||
amount: event.amount
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to handle invoice generation:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle market order events (new orders)
|
||||
const handleMarketOrder = async (event: any, senderPubkey: string) => {
|
||||
try {
|
||||
console.log('Processing market order:', event)
|
||||
|
||||
// Check if this order already exists
|
||||
const existingOrder = Object.values(marketStore.orders).find(
|
||||
order => order.id === event.orderId || order.nostrEventId === event.id
|
||||
)
|
||||
|
||||
if (existingOrder) {
|
||||
console.log('Order already exists, updating with new information:', existingOrder.id)
|
||||
|
||||
// Update the existing order with any new information
|
||||
const updatedOrder = {
|
||||
...existingOrder,
|
||||
...event,
|
||||
updatedAt: Math.floor(Date.now() / 1000)
|
||||
}
|
||||
|
||||
// If there's invoice information, update it
|
||||
if (event.lightningInvoice) {
|
||||
updatedOrder.lightningInvoice = event.lightningInvoice
|
||||
updatedOrder.paymentHash = event.paymentHash
|
||||
updatedOrder.paymentStatus = event.paymentStatus || 'pending'
|
||||
updatedOrder.paymentRequest = event.paymentRequest
|
||||
}
|
||||
|
||||
// Update the order in the store
|
||||
marketStore.updateOrder(existingOrder.id, updatedOrder)
|
||||
|
||||
console.log('Updated existing order:', {
|
||||
orderId: existingOrder.id,
|
||||
hasInvoice: !!updatedOrder.lightningInvoice,
|
||||
paymentStatus: updatedOrder.paymentStatus
|
||||
})
|
||||
|
||||
return
|
||||
console.log('Order updated with payment request:', existingOrder.id)
|
||||
} else {
|
||||
console.warn('Order not found for payment request:', paymentData.id)
|
||||
}
|
||||
|
||||
// Create a basic order object from the event data
|
||||
const orderData: Partial<Order> = {
|
||||
id: event.orderId,
|
||||
nostrEventId: event.id,
|
||||
buyerPubkey: event.pubkey || '',
|
||||
sellerPubkey: event.sellerPubkey || '',
|
||||
items: event.items || [],
|
||||
total: event.total || 0,
|
||||
currency: event.currency || 'sat',
|
||||
status: 'pending' as OrderStatus,
|
||||
createdAt: event.createdAt || Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
// Add invoice details if present
|
||||
...(event.lightningInvoice && {
|
||||
lightningInvoice: {
|
||||
checking_id: event.lightningInvoice.checking_id || event.lightningInvoice.payment_hash || '',
|
||||
payment_hash: event.lightningInvoice.payment_hash || '',
|
||||
wallet_id: event.lightningInvoice.wallet_id || '',
|
||||
amount: event.lightningInvoice.amount || 0,
|
||||
fee: event.lightningInvoice.fee || 0,
|
||||
bolt11: event.lightningInvoice.bolt11 || event.lightningInvoice.payment_request || '',
|
||||
status: 'pending',
|
||||
memo: event.lightningInvoice.memo || '',
|
||||
expiry: event.lightningInvoice.expiry || '',
|
||||
preimage: event.lightningInvoice.preimage || '',
|
||||
extra: event.lightningInvoice.extra || {},
|
||||
created_at: event.lightningInvoice.created_at || '',
|
||||
updated_at: event.lightningInvoice.updated_at || ''
|
||||
},
|
||||
paymentHash: event.lightningInvoice.payment_hash || '',
|
||||
paymentStatus: 'pending',
|
||||
paymentRequest: event.lightningInvoice.bolt11 || event.lightningInvoice.payment_request || '',
|
||||
updatedAt: Date.now()
|
||||
})
|
||||
}
|
||||
|
||||
// Create the order using the store method
|
||||
const order = marketStore.createOrder(orderData)
|
||||
|
||||
console.log('Created order from market event:', {
|
||||
orderId: order.id,
|
||||
total: order.total,
|
||||
status: order.status
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to handle market order:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Start listening for order events
|
||||
const startListening = async () => {
|
||||
if (!isReady.value) {
|
||||
console.warn('Cannot start listening: not ready')
|
||||
return
|
||||
}
|
||||
// Handle order status update (type 2)
|
||||
const handleOrderStatusUpdate = async (statusData: OrderStatusEvent, _senderPubkey: string) => {
|
||||
console.log('Received order status update:', statusData)
|
||||
|
||||
try {
|
||||
await subscribeToOrderEvents()
|
||||
console.log('Started listening for order events')
|
||||
} catch (error) {
|
||||
console.error('Failed to start listening for order events:', error)
|
||||
// Update order status in local state
|
||||
if (statusData.paid !== undefined) {
|
||||
console.log(`Order ${statusData.id} payment status: ${statusData.paid}`)
|
||||
}
|
||||
if (statusData.shipped !== undefined) {
|
||||
console.log(`Order ${statusData.id} shipping status: ${statusData.shipped}`)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop listening for order events
|
||||
const stopListening = () => {
|
||||
// Unsubscribe from order events
|
||||
const unsubscribeFromOrderEvents = () => {
|
||||
if (subscriptionId.value) {
|
||||
// Use the cleanup method from relayHub
|
||||
relayHub.cleanup()
|
||||
subscriptionId.value = null
|
||||
}
|
||||
isSubscribed.value = false
|
||||
console.log('Stopped listening for order events')
|
||||
console.log('Unsubscribed from order events')
|
||||
}
|
||||
|
||||
// Clean up old processed events
|
||||
const cleanupProcessedEvents = () => {
|
||||
// const now = Date.now()
|
||||
// const cutoff = now - (24 * 60 * 60 * 1000) // 24 hours ago
|
||||
|
||||
// Remove old event IDs (this is a simple cleanup, could be more sophisticated)
|
||||
if (processedEventIds.value.size > 1000) {
|
||||
processedEventIds.value.clear()
|
||||
console.log('Cleaned up processed event IDs')
|
||||
// Watch for ready state changes
|
||||
const watchReadyState = () => {
|
||||
if (isReady.value && !isSubscribed.value) {
|
||||
subscribeToOrderEvents()
|
||||
} else if (!isReady.value && isSubscribed.value) {
|
||||
unsubscribeFromOrderEvents()
|
||||
}
|
||||
}
|
||||
|
||||
// Watch for authentication changes
|
||||
const watchAuthChanges = () => {
|
||||
if (auth.isAuthenticated && relayHub.isConnected.value) {
|
||||
subscribeToOrderEvents()
|
||||
} else {
|
||||
unsubscribeFromOrderEvents()
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize subscription when ready
|
||||
const initialize = () => {
|
||||
if (isReady.value) {
|
||||
subscribeToOrderEvents()
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
const cleanup = () => {
|
||||
unsubscribeFromOrderEvents()
|
||||
processedEventIds.value.clear()
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
isSubscribed,
|
||||
lastEventTimestamp,
|
||||
isSubscribed: computed(() => isSubscribed.value),
|
||||
isReady: computed(() => isReady.value),
|
||||
lastEventTimestamp: computed(() => lastEventTimestamp.value),
|
||||
|
||||
// Methods
|
||||
startListening,
|
||||
stopListening,
|
||||
subscribeToOrderEvents,
|
||||
cleanupProcessedEvents
|
||||
unsubscribeFromOrderEvents,
|
||||
initialize,
|
||||
cleanup,
|
||||
watchReadyState,
|
||||
watchAuthChanges
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const orderEvents = useOrderEvents()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue