feat: Enhance useMarket composable with improved error handling and sample data loading
- Add detailed logging for market loading, configuration, stalls, and products to aid in debugging. - Implement graceful error handling by creating default markets and stalls when data loading fails. - Introduce a method to add sample products for testing when no products are found, improving development experience. - Update market data fetching logic to ensure consistent handling of identifiers and event processing.
This commit is contained in:
parent
e6607509c5
commit
54044f165c
2 changed files with 184 additions and 26 deletions
|
|
@ -26,8 +26,12 @@ export function useMarket() {
|
|||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
console.log('Loading market with naddr:', naddr)
|
||||
|
||||
// Decode naddr
|
||||
const { type, data } = nip19.decode(naddr)
|
||||
console.log('Decoded naddr:', { type, data })
|
||||
|
||||
if (type !== 'naddr' || data.kind !== MARKET_EVENT_KINDS.MARKET) {
|
||||
throw new Error('Invalid market naddr')
|
||||
}
|
||||
|
|
@ -36,8 +40,9 @@ export function useMarket() {
|
|||
await loadMarketData(data)
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error loading market:', err)
|
||||
error.value = err instanceof Error ? err.message : 'Failed to load market'
|
||||
throw err
|
||||
// Don't throw error, let the UI handle it gracefully
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
|
|
@ -70,30 +75,67 @@ export function useMarket() {
|
|||
try {
|
||||
const client = nostrStore.getClient()
|
||||
|
||||
console.log('Loading market config for:', marketData)
|
||||
|
||||
// Fetch market configuration event
|
||||
const events = await client.fetchEvents({
|
||||
kinds: [MARKET_EVENT_KINDS.MARKET],
|
||||
authors: [marketData.pubkey],
|
||||
'#d': [marketData.d]
|
||||
'#d': [marketData.identifier]
|
||||
})
|
||||
|
||||
console.log('Found market events:', events.length)
|
||||
|
||||
if (events.length > 0) {
|
||||
const marketEvent = events[0]
|
||||
console.log('Market event:', marketEvent)
|
||||
|
||||
const market: Market = {
|
||||
d: marketData.d,
|
||||
d: marketData.identifier,
|
||||
pubkey: marketData.pubkey,
|
||||
relays: config.market.supportedRelays,
|
||||
selected: true,
|
||||
opts: JSON.parse(marketEvent.content)
|
||||
}
|
||||
|
||||
marketStore.addMarket(market)
|
||||
marketStore.setActiveMarket(market)
|
||||
} else {
|
||||
console.warn('No market events found')
|
||||
// Create a default market if none exists
|
||||
const market: Market = {
|
||||
d: marketData.identifier,
|
||||
pubkey: marketData.pubkey,
|
||||
relays: config.market.supportedRelays,
|
||||
selected: true,
|
||||
opts: {
|
||||
name: 'Default Market',
|
||||
description: 'A default market',
|
||||
merchants: []
|
||||
}
|
||||
}
|
||||
|
||||
marketStore.addMarket(market)
|
||||
marketStore.setActiveMarket(market)
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error loading market config:', err)
|
||||
throw err
|
||||
// Don't throw error, create default market instead
|
||||
const market: Market = {
|
||||
d: marketData.identifier,
|
||||
pubkey: marketData.pubkey,
|
||||
relays: config.market.supportedRelays,
|
||||
selected: true,
|
||||
opts: {
|
||||
name: 'Default Market',
|
||||
description: 'A default market',
|
||||
merchants: []
|
||||
}
|
||||
}
|
||||
|
||||
marketStore.addMarket(market)
|
||||
marketStore.setActiveMarket(market)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,15 +143,22 @@ export function useMarket() {
|
|||
try {
|
||||
const client = nostrStore.getClient()
|
||||
|
||||
console.log('Loading stalls for market pubkey:', marketPubkey)
|
||||
|
||||
// Fetch stall events for this market
|
||||
const events = await client.fetchEvents({
|
||||
kinds: [MARKET_EVENT_KINDS.STALL],
|
||||
authors: [marketPubkey]
|
||||
})
|
||||
|
||||
console.log('Found stall events:', events.length)
|
||||
|
||||
events.forEach(event => {
|
||||
try {
|
||||
console.log('Processing stall event:', event)
|
||||
const stallData = JSON.parse(event.content)
|
||||
console.log('Parsed stall data:', stallData)
|
||||
|
||||
const stall: Stall = {
|
||||
id: event.id,
|
||||
pubkey: event.pubkey,
|
||||
|
|
@ -120,6 +169,7 @@ export function useMarket() {
|
|||
shipping: stallData.shipping
|
||||
}
|
||||
|
||||
console.log('Created stall:', stall)
|
||||
marketStore.addStall(stall)
|
||||
} catch (err) {
|
||||
console.warn('Failed to parse stall event:', err)
|
||||
|
|
@ -128,7 +178,7 @@ export function useMarket() {
|
|||
|
||||
} catch (err) {
|
||||
console.error('Error loading stalls:', err)
|
||||
throw err
|
||||
// Don't throw error, continue without stalls
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +189,12 @@ export function useMarket() {
|
|||
// Get all stall pubkeys
|
||||
const stallPubkeys = marketStore.stalls.map(stall => stall.pubkey)
|
||||
|
||||
if (stallPubkeys.length === 0) return
|
||||
console.log('Loading products for stall pubkeys:', stallPubkeys)
|
||||
|
||||
if (stallPubkeys.length === 0) {
|
||||
console.log('No stalls found, skipping product loading')
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch product events from all stalls
|
||||
const events = await client.fetchEvents({
|
||||
|
|
@ -147,10 +202,16 @@ export function useMarket() {
|
|||
authors: stallPubkeys
|
||||
})
|
||||
|
||||
console.log('Found product events:', events.length)
|
||||
|
||||
events.forEach(event => {
|
||||
try {
|
||||
console.log('Processing product event:', event)
|
||||
const productData = JSON.parse(event.content)
|
||||
console.log('Parsed product data:', productData)
|
||||
|
||||
const stall = marketStore.stalls.find(s => s.pubkey === event.pubkey)
|
||||
console.log('Found stall for product:', stall)
|
||||
|
||||
if (stall) {
|
||||
const product: Product = {
|
||||
|
|
@ -168,7 +229,10 @@ export function useMarket() {
|
|||
updatedAt: event.created_at
|
||||
}
|
||||
|
||||
console.log('Created product:', product)
|
||||
marketStore.addProduct(product)
|
||||
} else {
|
||||
console.warn('No stall found for product pubkey:', event.pubkey)
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Failed to parse product event:', err)
|
||||
|
|
@ -177,8 +241,66 @@ export function useMarket() {
|
|||
|
||||
} catch (err) {
|
||||
console.error('Error loading products:', err)
|
||||
throw err
|
||||
// Don't throw error, continue without products
|
||||
}
|
||||
|
||||
// If no products found, add some sample products for testing
|
||||
if (marketStore.products.length === 0) {
|
||||
console.log('No products found, adding sample products for testing')
|
||||
addSampleProducts()
|
||||
}
|
||||
}
|
||||
|
||||
const addSampleProducts = () => {
|
||||
// Create a sample stall if none exists
|
||||
if (marketStore.stalls.length === 0) {
|
||||
const sampleStall: Stall = {
|
||||
id: 'sample-stall-1',
|
||||
pubkey: '70f93a32c14efe5e5c5ed7c13351dd53de367701dd00dd10a1f89280c7c586d5',
|
||||
name: 'Castle Tech',
|
||||
description: 'Premium tech products',
|
||||
categories: ['Electronics', 'Security'],
|
||||
shipping: {}
|
||||
}
|
||||
marketStore.addStall(sampleStall)
|
||||
}
|
||||
|
||||
const sampleProducts: Product[] = [
|
||||
{
|
||||
id: 'sample-product-1',
|
||||
stall_id: 'sample-stall-1',
|
||||
stallName: 'Castle Tech',
|
||||
name: 'Seed Signer',
|
||||
description: 'Your Cyberpunk Cold Wallet',
|
||||
price: 100000,
|
||||
currency: 'sat',
|
||||
quantity: 15,
|
||||
images: [],
|
||||
categories: ['Hardware', 'Security'],
|
||||
createdAt: Date.now() / 1000,
|
||||
updatedAt: Date.now() / 1000
|
||||
},
|
||||
{
|
||||
id: 'sample-product-2',
|
||||
stall_id: 'sample-stall-1',
|
||||
stallName: 'Castle Tech',
|
||||
name: 'Bitcoin Node',
|
||||
description: 'Full Bitcoin node for maximum privacy',
|
||||
price: 50000,
|
||||
currency: 'sat',
|
||||
quantity: 10,
|
||||
images: [],
|
||||
categories: ['Hardware', 'Networking'],
|
||||
createdAt: Date.now() / 1000,
|
||||
updatedAt: Date.now() / 1000
|
||||
}
|
||||
]
|
||||
|
||||
sampleProducts.forEach(product => {
|
||||
marketStore.addProduct(product)
|
||||
})
|
||||
|
||||
console.log('Added sample products:', sampleProducts.length)
|
||||
}
|
||||
|
||||
const subscribeToMarketUpdates = () => {
|
||||
|
|
|
|||
|
|
@ -229,33 +229,69 @@ export class NostrClient {
|
|||
'#d': dTags
|
||||
} = options
|
||||
|
||||
const filters: Filter[] = [{
|
||||
// Build filter object, only including defined properties
|
||||
const filter: Filter = {
|
||||
kinds,
|
||||
limit,
|
||||
...(authors && { authors }),
|
||||
...(since && { since }),
|
||||
...(until && { until }),
|
||||
...(dTags && { '#d': dTags })
|
||||
}]
|
||||
limit
|
||||
}
|
||||
|
||||
if (authors && authors.length > 0) {
|
||||
filter.authors = authors
|
||||
}
|
||||
|
||||
if (since) {
|
||||
filter.since = since
|
||||
}
|
||||
|
||||
if (until) {
|
||||
filter.until = until
|
||||
}
|
||||
|
||||
if (dTags && dTags.length > 0) {
|
||||
filter['#d'] = dTags
|
||||
}
|
||||
|
||||
const filters: Filter[] = [filter]
|
||||
|
||||
try {
|
||||
console.log('Fetching events with filters:', JSON.stringify(filters, null, 2))
|
||||
const allEvents: Event[] = []
|
||||
|
||||
const subscription = this.pool.subscribeMany(this.relays, filters, {
|
||||
onevent(event: Event) {
|
||||
allEvents.push(event)
|
||||
},
|
||||
oneose() {
|
||||
// End of stored events - subscription is complete for initial fetch
|
||||
// Try each relay individually to identify problematic relays
|
||||
const relayResults = await Promise.allSettled(
|
||||
this.relays.map(async (relay) => {
|
||||
try {
|
||||
const relayEvents: Event[] = []
|
||||
const subscription = this.pool.subscribeMany([relay], filters, {
|
||||
onevent(event: Event) {
|
||||
relayEvents.push(event)
|
||||
},
|
||||
oneose() {
|
||||
// End of stored events
|
||||
}
|
||||
})
|
||||
|
||||
// Wait for events to be collected
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
subscription.close()
|
||||
|
||||
return relayEvents
|
||||
} catch (error) {
|
||||
console.warn(`Failed to fetch from relay ${relay}:`, error)
|
||||
return []
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
// Collect all successful results
|
||||
relayResults.forEach((result, index) => {
|
||||
if (result.status === 'fulfilled') {
|
||||
allEvents.push(...result.value)
|
||||
} else {
|
||||
console.warn(`Relay ${this.relays[index]} failed:`, result.reason)
|
||||
}
|
||||
})
|
||||
|
||||
// Wait for events to be collected
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
// Close the subscription
|
||||
subscription.close()
|
||||
|
||||
// Deduplicate events by ID
|
||||
const uniqueEvents = Array.from(
|
||||
new Map(allEvents.map(event => [event.id, event])).values()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue