Enhance ReceiveDialog and WalletService for LNURL handling and transaction tagging
- Added functionality to encode LNURL for QR code generation in ReceiveDialog, improving payment link sharing. - Updated WalletService to include a tag property for transactions, allowing for better categorization and display in WalletPage. - Enhanced WalletPage to display transaction tags, improving user visibility of transaction details. These changes improve the user experience by providing clearer payment information and enhancing the functionality of the wallet module.
This commit is contained in:
parent
86b1710030
commit
981fc23422
3 changed files with 52 additions and 10 deletions
|
|
@ -3,6 +3,7 @@ import { ref, computed, nextTick } from 'vue'
|
||||||
import { useForm } from 'vee-validate'
|
import { useForm } from 'vee-validate'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import * as z from 'zod'
|
import * as z from 'zod'
|
||||||
|
import { nip19 } from 'nostr-tools'
|
||||||
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
|
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
|
||||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
|
|
@ -106,13 +107,29 @@ async function copyToClipboard(text: string, field: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function encodeLNURL(url: string): string {
|
||||||
|
try {
|
||||||
|
// Convert URL to bytes
|
||||||
|
const bytes = new TextEncoder().encode(url)
|
||||||
|
// Encode as bech32 with 'lnurl' prefix
|
||||||
|
const bech32 = nip19.encodeBytes('lnurl', bytes)
|
||||||
|
// Return with lightning: prefix in uppercase
|
||||||
|
return `lightning:${bech32.toUpperCase()}`
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to encode LNURL:', error)
|
||||||
|
return url // Fallback to original URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function generateQRCode(data: string) {
|
async function generateQRCode(data: string) {
|
||||||
if (!data) return
|
if (!data) return
|
||||||
|
|
||||||
isLoadingQR.value = true
|
isLoadingQR.value = true
|
||||||
try {
|
try {
|
||||||
|
// Encode LNURL with proper bech32 format and lightning: prefix
|
||||||
|
const encodedLNURL = encodeLNURL(data)
|
||||||
// Use the existing PaymentService QR code generation
|
// Use the existing PaymentService QR code generation
|
||||||
qrCode.value = await paymentService?.generateQRCode(data)
|
qrCode.value = await paymentService?.generateQRCode(encodedLNURL)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to generate QR code:', error)
|
console.error('Failed to generate QR code:', error)
|
||||||
toastService?.error('Failed to generate QR code')
|
toastService?.error('Failed to generate QR code')
|
||||||
|
|
@ -331,9 +348,29 @@ function onOpenChange(open: boolean) {
|
||||||
<QrCode class="h-12 w-12 text-muted-foreground opacity-50" />
|
<QrCode class="h-12 w-12 text-muted-foreground opacity-50" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- LNURL -->
|
<!-- Encoded LNURL (for QR) -->
|
||||||
<div class="w-full space-y-2">
|
<div class="w-full space-y-2">
|
||||||
<Label>LNURL</Label>
|
<Label>LNURL (Encoded)</Label>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<Input
|
||||||
|
:value="selectedPayLink.lnurl ? encodeLNURL(selectedPayLink.lnurl) : ''"
|
||||||
|
readonly
|
||||||
|
class="font-mono text-xs"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
@click="copyToClipboard(selectedPayLink.lnurl ? encodeLNURL(selectedPayLink.lnurl) : '', 'encoded-lnurl')"
|
||||||
|
>
|
||||||
|
<Check v-if="copiedField === 'encoded-lnurl'" class="h-4 w-4 text-green-600" />
|
||||||
|
<Copy v-else class="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Raw LNURL -->
|
||||||
|
<div class="w-full space-y-2">
|
||||||
|
<Label>LNURL (Raw)</Label>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
:value="selectedPayLink.lnurl"
|
:value="selectedPayLink.lnurl"
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ export interface PaymentTransaction {
|
||||||
type: 'sent' | 'received'
|
type: 'sent' | 'received'
|
||||||
status: 'pending' | 'confirmed' | 'failed'
|
status: 'pending' | 'confirmed' | 'failed'
|
||||||
fee?: number
|
fee?: number
|
||||||
|
tag?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class WalletService extends BaseService {
|
export default class WalletService extends BaseService {
|
||||||
|
|
@ -274,7 +275,8 @@ export default class WalletService extends BaseService {
|
||||||
timestamp: payment.time ? new Date(payment.time * 1000) : new Date(),
|
timestamp: payment.time ? new Date(payment.time * 1000) : new Date(),
|
||||||
type: payment.amount > 0 ? 'received' : 'sent',
|
type: payment.amount > 0 ? 'received' : 'sent',
|
||||||
status: payment.pending ? 'pending' : 'confirmed',
|
status: payment.pending ? 'pending' : 'confirmed',
|
||||||
fee: payment.fee ? payment.fee / 1000 : undefined
|
fee: payment.fee ? payment.fee / 1000 : undefined,
|
||||||
|
tag: payment.tag || (payment.extra && payment.extra.tag) || null
|
||||||
})).sort((a: PaymentTransaction, b: PaymentTransaction) =>
|
})).sort((a: PaymentTransaction, b: PaymentTransaction) =>
|
||||||
b.timestamp.getTime() - a.timestamp.getTime()
|
b.timestamp.getTime() - a.timestamp.getTime()
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,9 @@ onMounted(() => {
|
||||||
<Badge :variant="getStatusColor(tx.status)" class="text-xs">
|
<Badge :variant="getStatusColor(tx.status)" class="text-xs">
|
||||||
{{ tx.status }}
|
{{ tx.status }}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
<Badge v-if="tx.tag" variant="outline" class="text-xs">
|
||||||
|
{{ tx.tag }}
|
||||||
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue