Refactor ReceiveDialog.vue for Lightning invoice creation

- Updated the form to create Lightning invoices instead of LNURL addresses, changing the validation schema and input fields accordingly.
- Introduced new state management for created invoices and adjusted the submission logic to handle invoice creation.
- Enhanced the UI to display invoice details, including amount, memo, and QR code generation for the invoice.
- Removed unused components and streamlined the dialog's functionality for a more focused user experience.

These changes improve the functionality and user interface of the ReceiveDialog component, facilitating easier invoice management for Bitcoin payments.
This commit is contained in:
padreug 2025-09-18 21:44:24 +02:00
parent 27070c0390
commit 21e1c8f7c0
3 changed files with 280 additions and 318 deletions

View file

@ -21,6 +21,23 @@ export interface SendPaymentRequest {
comment?: string
}
export interface CreateInvoiceRequest {
amount: number
memo: string
expiry?: number // Optional expiry in seconds
}
export interface Invoice {
payment_hash: string
bolt11: string // The BOLT11 invoice
payment_request: string // Same as bolt11, for compatibility
checking_id: string
amount: number
memo: string
time: number
expiry: number | null
}
export interface PaymentTransaction {
id: string
amount: number
@ -47,6 +64,7 @@ export default class WalletService extends BaseService {
private _transactions = ref<PaymentTransaction[]>([])
private _isCreatingPayLink = ref(false)
private _isSendingPayment = ref(false)
private _isCreatingInvoice = ref(false)
private _error = ref<string | null>(null)
// Public reactive getters
@ -54,6 +72,7 @@ export default class WalletService extends BaseService {
readonly transactions = computed(() => this._transactions.value)
readonly isCreatingPayLink = computed(() => this._isCreatingPayLink.value)
readonly isSendingPayment = computed(() => this._isSendingPayment.value)
readonly isCreatingInvoice = computed(() => this._isCreatingInvoice.value)
readonly error = computed(() => this._error.value)
protected async onInitialize(): Promise<void> {
@ -148,6 +167,63 @@ export default class WalletService extends BaseService {
}
}
/**
* Create a Lightning invoice for receiving payments
*/
async createInvoice(request: CreateInvoiceRequest): Promise<Invoice | null> {
this._isCreatingInvoice.value = true
this._error.value = null
try {
const invoiceKey = this.paymentService?.getPreferredWalletInvoiceKey()
if (!invoiceKey) {
throw new Error('No invoice key available')
}
// Create invoice via LNbits payments API
const response = await fetch(`${config.api.baseUrl}/api/v1/payments`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': invoiceKey
},
body: JSON.stringify({
out: false, // Incoming payment (receiving)
amount: request.amount,
unit: 'sat',
memo: request.memo,
expiry: request.expiry || 3600 // Default 1 hour expiry
})
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.detail || 'Failed to create invoice')
}
const rawInvoice = await response.json()
console.log('Raw invoice response:', rawInvoice)
// Process the response to fix data issues
const invoice: Invoice = {
...rawInvoice,
payment_request: rawInvoice.bolt11, // Copy bolt11 to payment_request for compatibility
amount: rawInvoice.amount / 1000, // Convert from millisats to sats
expiry: rawInvoice.expiry ? this.parseExpiryToSeconds(rawInvoice.expiry) : null
}
console.log('Processed invoice:', invoice)
return invoice
} catch (error) {
console.error('Failed to create invoice:', error)
this._error.value = error instanceof Error ? error.message : 'Failed to create invoice'
return null
} finally {
this._isCreatingInvoice.value = false
}
}
/**
* Send a Lightning payment
*/
@ -351,6 +427,21 @@ export default class WalletService extends BaseService {
])
}
/**
* Parse expiry date string to seconds from now
*/
private parseExpiryToSeconds(expiryStr: string): number {
try {
const expiryDate = new Date(expiryStr)
const now = new Date()
const diffMs = expiryDate.getTime() - now.getTime()
return Math.max(0, Math.floor(diffMs / 1000)) // Return seconds, minimum 0
} catch (error) {
console.error('Failed to parse expiry date:', expiryStr, error)
return 3600 // Default to 1 hour
}
}
/**
* Add a new transaction from WebSocket notification
*/
@ -390,4 +481,4 @@ export default class WalletService extends BaseService {
tag: payment.tag || null
}
}
}
}