Implement copy functionality for LNURL and Lightning Address in WalletPage.vue
- Added a copyToClipboard function to enable users to copy LNURL and Lightning Address directly from the wallet interface. - Enhanced the QR code display to allow clicking for copying the LNURL. - Introduced visual feedback with icons indicating successful copy actions. These changes improve user experience by simplifying the process of sharing wallet information.
This commit is contained in:
parent
5293f2f4c2
commit
27070c0390
1 changed files with 53 additions and 9 deletions
|
|
@ -6,7 +6,7 @@ import { Button } from '@/components/ui/button'
|
|||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { RefreshCw, Send, QrCode, ArrowUpRight, ArrowDownLeft, Clock, Wallet } from 'lucide-vue-next'
|
||||
import { RefreshCw, Send, QrCode, ArrowUpRight, ArrowDownLeft, Clock, Wallet, Copy, Check } from 'lucide-vue-next'
|
||||
import ReceiveDialog from '../components/ReceiveDialog.vue'
|
||||
import SendDialog from '../components/SendDialog.vue'
|
||||
import { format } from 'date-fns'
|
||||
|
|
@ -16,6 +16,7 @@ import { nip19 } from 'nostr-tools'
|
|||
const walletService = injectService(SERVICE_TOKENS.WALLET_SERVICE) as any
|
||||
const paymentService = injectService(SERVICE_TOKENS.PAYMENT_SERVICE) as any
|
||||
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) as any
|
||||
const toastService = injectService(SERVICE_TOKENS.TOAST_SERVICE) as any
|
||||
|
||||
// State
|
||||
const showReceiveDialog = ref(false)
|
||||
|
|
@ -23,6 +24,7 @@ const showSendDialog = ref(false)
|
|||
const selectedTab = ref('transactions')
|
||||
const defaultQrCode = ref<string | null>(null)
|
||||
const isGeneratingQR = ref(false)
|
||||
const copiedField = ref<string | null>(null)
|
||||
|
||||
// Computed
|
||||
const transactions = computed(() => walletService?.transactions?.value || [])
|
||||
|
|
@ -119,6 +121,31 @@ async function generateDefaultQR() {
|
|||
}
|
||||
}
|
||||
|
||||
// Copy functionality
|
||||
async function copyToClipboard(text: string, field: string) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text)
|
||||
copiedField.value = field
|
||||
toastService?.success('Copied to clipboard!')
|
||||
|
||||
setTimeout(() => {
|
||||
copiedField.value = null
|
||||
}, 2000)
|
||||
} catch (error) {
|
||||
console.error('Failed to copy:', error)
|
||||
toastService?.error('Failed to copy to clipboard')
|
||||
}
|
||||
}
|
||||
|
||||
// Click handler for QR code to copy LNURL
|
||||
function handleQRClick() {
|
||||
if (firstPayLink.value?.lnurl) {
|
||||
// Encode LNURL with proper bech32 format and lightning: prefix (same as QR code)
|
||||
const encodedLNURL = encodeLNURL(firstPayLink.value.lnurl)
|
||||
copyToClipboard(encodedLNURL, 'qr-lnurl')
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize on mount
|
||||
onMounted(async () => {
|
||||
await refresh()
|
||||
|
|
@ -205,12 +232,17 @@ onMounted(async () => {
|
|||
<div v-if="isGeneratingQR" class="w-48 h-48 flex items-center justify-center bg-muted rounded-lg">
|
||||
<RefreshCw class="h-8 w-8 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
<div v-else-if="defaultQrCode" class="bg-white p-4 rounded-lg">
|
||||
<img
|
||||
:src="defaultQrCode"
|
||||
alt="LNURL QR Code"
|
||||
class="w-48 h-48"
|
||||
/>
|
||||
<div v-else-if="defaultQrCode" class="text-center">
|
||||
<div class="bg-white p-4 rounded-lg cursor-pointer hover:bg-gray-50 transition-colors" @click="handleQRClick" title="Click to copy LNURL">
|
||||
<img
|
||||
:src="defaultQrCode"
|
||||
alt="LNURL QR Code"
|
||||
class="w-48 h-48"
|
||||
/>
|
||||
</div>
|
||||
<p class="text-xs text-muted-foreground mt-2">
|
||||
Click QR code to copy LNURL
|
||||
</p>
|
||||
</div>
|
||||
<div v-else class="w-48 h-48 flex items-center justify-center bg-muted rounded-lg">
|
||||
<QrCode class="h-12 w-12 text-muted-foreground opacity-50" />
|
||||
|
|
@ -228,8 +260,20 @@ onMounted(async () => {
|
|||
|
||||
<div v-if="firstPayLink.lnaddress">
|
||||
<h4 class="font-medium mb-2">Lightning Address</h4>
|
||||
<div class="font-mono text-sm bg-muted px-3 py-2 rounded">
|
||||
{{ firstPayLink.lnaddress }}
|
||||
<div class="flex gap-2">
|
||||
<div class="font-mono text-sm bg-muted px-3 py-2 rounded flex-1">
|
||||
{{ firstPayLink.lnaddress }}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@click="copyToClipboard(firstPayLink.lnaddress || '', 'lightning-address')"
|
||||
class="h-auto px-2"
|
||||
title="Copy Lightning Address"
|
||||
>
|
||||
<Check v-if="copiedField === 'lightning-address'" class="h-4 w-4 text-green-600" />
|
||||
<Copy v-else class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue