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 { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
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 ReceiveDialog from '../components/ReceiveDialog.vue'
|
||||||
import SendDialog from '../components/SendDialog.vue'
|
import SendDialog from '../components/SendDialog.vue'
|
||||||
import { format } from 'date-fns'
|
import { format } from 'date-fns'
|
||||||
|
|
@ -16,6 +16,7 @@ import { nip19 } from 'nostr-tools'
|
||||||
const walletService = injectService(SERVICE_TOKENS.WALLET_SERVICE) as any
|
const walletService = injectService(SERVICE_TOKENS.WALLET_SERVICE) as any
|
||||||
const paymentService = injectService(SERVICE_TOKENS.PAYMENT_SERVICE) as any
|
const paymentService = injectService(SERVICE_TOKENS.PAYMENT_SERVICE) as any
|
||||||
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) as any
|
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) as any
|
||||||
|
const toastService = injectService(SERVICE_TOKENS.TOAST_SERVICE) as any
|
||||||
|
|
||||||
// State
|
// State
|
||||||
const showReceiveDialog = ref(false)
|
const showReceiveDialog = ref(false)
|
||||||
|
|
@ -23,6 +24,7 @@ const showSendDialog = ref(false)
|
||||||
const selectedTab = ref('transactions')
|
const selectedTab = ref('transactions')
|
||||||
const defaultQrCode = ref<string | null>(null)
|
const defaultQrCode = ref<string | null>(null)
|
||||||
const isGeneratingQR = ref(false)
|
const isGeneratingQR = ref(false)
|
||||||
|
const copiedField = ref<string | null>(null)
|
||||||
|
|
||||||
// Computed
|
// Computed
|
||||||
const transactions = computed(() => walletService?.transactions?.value || [])
|
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
|
// Initialize on mount
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await refresh()
|
await refresh()
|
||||||
|
|
@ -205,13 +232,18 @@ onMounted(async () => {
|
||||||
<div v-if="isGeneratingQR" class="w-48 h-48 flex items-center justify-center bg-muted rounded-lg">
|
<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" />
|
<RefreshCw class="h-8 w-8 animate-spin text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="defaultQrCode" class="bg-white p-4 rounded-lg">
|
<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
|
<img
|
||||||
:src="defaultQrCode"
|
:src="defaultQrCode"
|
||||||
alt="LNURL QR Code"
|
alt="LNURL QR Code"
|
||||||
class="w-48 h-48"
|
class="w-48 h-48"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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">
|
<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" />
|
<QrCode class="h-12 w-12 text-muted-foreground opacity-50" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -228,9 +260,21 @@ onMounted(async () => {
|
||||||
|
|
||||||
<div v-if="firstPayLink.lnaddress">
|
<div v-if="firstPayLink.lnaddress">
|
||||||
<h4 class="font-medium mb-2">Lightning Address</h4>
|
<h4 class="font-medium mb-2">Lightning Address</h4>
|
||||||
<div class="font-mono text-sm bg-muted px-3 py-2 rounded">
|
<div class="flex gap-2">
|
||||||
|
<div class="font-mono text-sm bg-muted px-3 py-2 rounded flex-1">
|
||||||
{{ firstPayLink.lnaddress }}
|
{{ firstPayLink.lnaddress }}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue