Payment Required
-
- {{ order.paymentStatus === 'paid' ? 'Paid' : 'Pending' }}
+
+ {{ isOrderPaid(order) ? 'Paid' : 'Pending' }}
@@ -237,7 +251,7 @@ import { auth } from '@/composables/useAuth'
import { useLightningPayment } from '../composables/useLightningPayment'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
-import { Package, Store, Zap, Copy, QrCode } from 'lucide-vue-next'
+import { Package, Store, Zap, Copy, QrCode, CheckCircle } from 'lucide-vue-next'
import { toast } from 'vue-sonner'
import type { OrderStatus } from '@/stores/market'
@@ -286,11 +300,20 @@ const sortedOrders = computed(() => {
const totalOrders = computed(() => allOrders.value.length)
const pendingOrders = computed(() => allOrders.value.filter(o => o.status === 'pending').length)
const paidOrders = computed(() => allOrders.value.filter(o => o.status === 'paid').length)
-const pendingPayments = computed(() => allOrders.value.filter(o => o.paymentStatus === 'pending').length)
+const pendingPayments = computed(() => allOrders.value.filter(o => !isOrderPaid(o)).length)
const isDevelopment = computed(() => import.meta.env.DEV)
// Methods
+const isOrderPaid = (order: Order) => {
+ // Prioritize the 'paid' field from Nostr status updates (type 2)
+ if (order.paid !== undefined) {
+ return order.paid
+ }
+ // Fallback to paymentStatus field
+ return order.paymentStatus === 'paid'
+}
+
const formatDate = (timestamp: number) => {
return new Date(timestamp * 1000).toLocaleDateString('en-US', {
year: 'numeric',
diff --git a/src/modules/market/composables/usePaymentStatusChecker.ts b/src/modules/market/composables/usePaymentStatusChecker.ts
new file mode 100644
index 0000000..fb2c608
--- /dev/null
+++ b/src/modules/market/composables/usePaymentStatusChecker.ts
@@ -0,0 +1,139 @@
+import { ref } from 'vue'
+import { useAuth } from '@/composables/useAuth'
+import { useMarketStore } from '../stores/market'
+
+// Simplified bolt11 parser to extract payment hash
+function parseBolt11(bolt11: string): { paymentHash?: string } {
+ try {
+ // Remove lightning: prefix if present
+ const cleanBolt11 = bolt11.replace(/^lightning:/, '')
+
+ // Very basic bolt11 parsing - in a real app you'd use a proper library
+ // For now, we'll return empty since this requires complex bech32 decoding
+ return {}
+ } catch (error) {
+ console.error('Failed to parse bolt11:', error)
+ return {}
+ }
+}
+
+export function usePaymentStatusChecker() {
+ const { currentUser } = useAuth()
+ const marketStore = useMarketStore()
+ const isChecking = ref(false)
+
+ // Check payment status via LNbits API using payment hash
+ async function checkPaymentStatusByHash(paymentHash: string, walletId?: string): Promise
{
+ if (!currentUser.value || !paymentHash) {
+ return false
+ }
+
+ try {
+ // Get wallet with admin key
+ const wallet = walletId
+ ? currentUser.value.wallets?.find((w: any) => w.id === walletId)
+ : currentUser.value.wallets?.find((w: any) => w.adminkey) // Use first wallet with admin key
+
+ if (!wallet || !wallet.adminkey) {
+ console.warn('No wallet with admin key found for payment status check')
+ return false
+ }
+
+ // Check payment status via LNbits API
+ const response = await fetch(`/api/v1/payments/${paymentHash}`, {
+ headers: {
+ 'accept': 'application/json',
+ 'X-API-KEY': wallet.adminkey,
+ },
+ })
+
+ if (response.ok) {
+ const payment = await response.json()
+ return payment.paid === true
+ } else {
+ console.warn('Payment not found or API error:', response.status)
+ return false
+ }
+ } catch (error) {
+ console.error('Failed to check payment status:', error)
+ return false
+ }
+ }
+
+ // Check payment status for a bolt11 invoice
+ async function checkPaymentStatusByBolt11(bolt11: string): Promise {
+ const parsed = parseBolt11(bolt11)
+ if (parsed.paymentHash) {
+ return await checkPaymentStatusByHash(parsed.paymentHash)
+ }
+ return false
+ }
+
+ // Check and update payment status for an order
+ async function checkAndUpdateOrderPaymentStatus(orderId: string): Promise {
+ if (isChecking.value) return false
+
+ const order = marketStore.orders[orderId]
+ if (!order || !order.paymentRequest) {
+ return false
+ }
+
+ try {
+ isChecking.value = true
+ console.log('🔍 Checking payment status for order:', orderId.slice(-8))
+
+ // Method 1: Check by bolt11 (if we can extract payment hash)
+ const isPaid = await checkPaymentStatusByBolt11(order.paymentRequest)
+
+ if (isPaid && order.paymentStatus !== 'paid') {
+ console.log('✅ Payment confirmed via API check for order:', orderId.slice(-8))
+
+ // Update order status
+ const updatedOrder = {
+ ...order,
+ status: 'paid' as const,
+ paymentStatus: 'paid' as const,
+ paidAt: Math.floor(Date.now() / 1000),
+ items: [...order.items] // Convert readonly to mutable
+ }
+
+ marketStore.updateOrder(orderId, updatedOrder)
+ return true
+ }
+
+ return isPaid
+ } catch (error) {
+ console.error('Failed to check payment status:', error)
+ return false
+ } finally {
+ isChecking.value = false
+ }
+ }
+
+ // Check payment status for all pending orders
+ async function checkAllPendingOrders(): Promise {
+ const pendingOrders = Object.values(marketStore.orders).filter(
+ order => order.paymentStatus === 'pending' && order.paymentRequest
+ )
+
+ if (pendingOrders.length === 0) {
+ return
+ }
+
+ console.log(`🔍 Checking payment status for ${pendingOrders.length} pending orders`)
+
+ for (const order of pendingOrders) {
+ await checkAndUpdateOrderPaymentStatus(order.id)
+ // Add small delay between requests to avoid overwhelming the API
+ await new Promise(resolve => setTimeout(resolve, 100))
+ }
+ }
+
+ return {
+ isChecking,
+ checkPaymentStatusByHash,
+ checkPaymentStatusByBolt11,
+ checkAndUpdateOrderPaymentStatus,
+ checkAllPendingOrders
+ }
+}
\ No newline at end of file
diff --git a/src/modules/market/services/nostrmarketService.ts b/src/modules/market/services/nostrmarketService.ts
index 4b305db..5cb03fb 100644
--- a/src/modules/market/services/nostrmarketService.ts
+++ b/src/modules/market/services/nostrmarketService.ts
@@ -411,39 +411,39 @@ export class NostrmarketService {
)
if (order) {
- // Update order status
+ // Create the updated order object with all status updates
+ const updatedOrder = {
+ ...order,
+ updatedAt: Math.floor(Date.now() / 1000),
+ items: [...order.items] // Convert readonly to mutable
+ }
+
+ // Update payment status
if (statusUpdate.paid !== undefined) {
- const newStatus = statusUpdate.paid ? 'paid' : 'pending'
- marketStore.updateOrderStatus(order.id, newStatus)
-
- // Also update payment status
- const updatedOrder = {
- ...order,
- paymentStatus: (statusUpdate.paid ? 'paid' : 'pending') as 'paid' | 'pending' | 'expired',
- paidAt: statusUpdate.paid ? Math.floor(Date.now() / 1000) : undefined,
- updatedAt: Math.floor(Date.now() / 1000),
- items: [...order.items] // Convert readonly to mutable
- }
- marketStore.updateOrder(order.id, updatedOrder)
+ updatedOrder.paid = statusUpdate.paid
+ updatedOrder.paymentStatus = (statusUpdate.paid ? 'paid' : 'pending') as 'paid' | 'pending' | 'expired'
+ updatedOrder.status = statusUpdate.paid ? 'paid' : 'pending'
+ updatedOrder.paidAt = statusUpdate.paid ? Math.floor(Date.now() / 1000) : undefined
}
+ // Update shipping status
if (statusUpdate.shipped !== undefined) {
- // Update shipping status if you have that field
- const updatedOrder = {
- ...order,
- shipped: statusUpdate.shipped,
- status: statusUpdate.shipped ? 'shipped' : order.status,
- updatedAt: Math.floor(Date.now() / 1000),
- items: [...order.items] // Convert readonly to mutable
+ updatedOrder.shipped = statusUpdate.shipped
+ if (statusUpdate.shipped && updatedOrder.status === 'paid') {
+ updatedOrder.status = 'shipped'
}
- marketStore.updateOrder(order.id, updatedOrder)
}
- console.log('Order status updated:', {
+ // Apply the update - this should trigger persistence
+ marketStore.updateOrder(order.id, updatedOrder)
+
+ console.log('Order status updated and persisted:', {
orderId: statusUpdate.id,
- paid: statusUpdate.paid,
- shipped: statusUpdate.shipped,
- newStatus: statusUpdate.paid ? 'paid' : 'pending'
+ paid: updatedOrder.paid,
+ shipped: updatedOrder.shipped,
+ paymentStatus: updatedOrder.paymentStatus,
+ status: updatedOrder.status,
+ paidAt: updatedOrder.paidAt
})
} else {
console.warn('Status update received for unknown order:', statusUpdate.id)
diff --git a/src/modules/market/stores/market.ts b/src/modules/market/stores/market.ts
index 404c061..4426339 100644
--- a/src/modules/market/stores/market.ts
+++ b/src/modules/market/stores/market.ts
@@ -403,7 +403,9 @@ export const useMarketStore = defineStore('market', () => {
...orderData,
id: orderData.id || generateOrderId(),
createdAt: Math.floor(Date.now() / 1000),
- updatedAt: Math.floor(Date.now() / 1000)
+ updatedAt: Math.floor(Date.now() / 1000),
+ paid: false, // Initialize as unpaid
+ paymentStatus: orderData.paymentStatus || 'pending' // Default to pending if not specified
}
orders.value[order.id] = order
@@ -682,7 +684,22 @@ export const useMarketStore = defineStore('market', () => {
try {
const storageKey = getUserStorageKey('market_orders')
localStorage.setItem(storageKey, JSON.stringify(orders.value))
- console.log('Saved orders to localStorage with key:', storageKey)
+
+ // Debug: Check what's being saved
+ const orderCount = Object.keys(orders.value).length
+ const paidOrders = Object.values(orders.value).filter(o => o.paymentStatus === 'paid' || o.status === 'paid')
+
+ console.log('💾 Saved orders to localStorage:', {
+ storageKey,
+ totalOrders: orderCount,
+ paidOrders: paidOrders.length,
+ orderStatuses: Object.values(orders.value).map(o => ({
+ id: o.id?.slice(-8),
+ status: o.status,
+ paymentStatus: o.paymentStatus,
+ hasPaymentRequest: !!o.paymentRequest
+ }))
+ })
} catch (error) {
console.warn('Failed to save orders to localStorage:', error)
}
@@ -695,7 +712,22 @@ export const useMarketStore = defineStore('market', () => {
if (stored) {
const parsedOrders = JSON.parse(stored)
orders.value = parsedOrders
- console.log('Loaded orders from localStorage with key:', storageKey, 'Orders count:', Object.keys(parsedOrders).length)
+
+ // Debug: Check payment status of loaded orders
+ const orderCount = Object.keys(parsedOrders).length
+ const paidOrders = Object.values(parsedOrders).filter((o: any) => o.paymentStatus === 'paid' || o.status === 'paid')
+
+ console.log('📦 Loaded orders from localStorage:', {
+ storageKey,
+ totalOrders: orderCount,
+ paidOrders: paidOrders.length,
+ orderStatuses: Object.values(parsedOrders).map((o: any) => ({
+ id: o.id?.slice(-8),
+ status: o.status,
+ paymentStatus: o.paymentStatus,
+ hasPaymentRequest: !!o.paymentRequest
+ }))
+ })
} else {
console.log('No orders found in localStorage for key:', storageKey)
// Clear any existing orders when switching users
diff --git a/src/modules/market/types/market.ts b/src/modules/market/types/market.ts
index 5c21145..3b038b0 100644
--- a/src/modules/market/types/market.ts
+++ b/src/modules/market/types/market.ts
@@ -69,6 +69,8 @@ export interface Order {
paymentHash?: string
paidAt?: number
paymentStatus?: 'pending' | 'paid' | 'expired'
+ paid?: boolean // Direct boolean field matching nostrmarket reference
+ shipped?: boolean // Shipping status from merchant updates
qrCodeDataUrl?: string
qrCodeLoading?: boolean
qrCodeError?: string | null