Enhance SendDialog and WalletPage with QR code scanning integration

- Added initialDestination prop to SendDialog for pre-filling the destination field.
- Implemented a watcher to update the destination field when initialDestination changes.
- Integrated QRScanner component into WalletPage, allowing users to scan QR codes for payment destinations.
- Updated SendDialog to accept scanned destination and improved user feedback with toast notifications.

These changes streamline the payment process by enabling QR code scanning directly within the wallet interface.
This commit is contained in:
padreug 2025-09-18 22:34:29 +02:00
parent 7b240fc5be
commit f94dc1d03c
2 changed files with 70 additions and 6 deletions

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed, ref, watch } from 'vue'
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
@ -14,6 +14,7 @@ import QRScanner from '@/components/ui/qr-scanner.vue'
interface Props {
open: boolean
initialDestination?: string
}
interface Emits {
@ -38,7 +39,7 @@ const formSchema = toTypedSchema(z.object({
const form = useForm({
validationSchema: formSchema,
initialValues: {
destination: '',
destination: props.initialDestination || '',
amount: 100,
comment: ''
}
@ -47,6 +48,13 @@ const form = useForm({
const { resetForm, values, meta, setFieldValue } = form
const isFormValid = computed(() => meta.value.valid)
// Watch for prop changes
watch(() => props.initialDestination, (newDestination) => {
if (newDestination) {
setFieldValue('destination', newDestination)
}
}, { immediate: true })
// State
const isSending = computed(() => walletService?.isSendingPayment?.value || false)
const showScanner = ref(false)

View file

@ -6,9 +6,11 @@ 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, Copy, Check } from 'lucide-vue-next'
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { RefreshCw, Send, QrCode, ArrowUpRight, ArrowDownLeft, Clock, Wallet, ScanLine, Copy, Check } from 'lucide-vue-next'
import ReceiveDialog from '../components/ReceiveDialog.vue'
import SendDialog from '../components/SendDialog.vue'
import QRScanner from '@/components/ui/qr-scanner.vue'
import { format } from 'date-fns'
import { nip19 } from 'nostr-tools'
@ -21,6 +23,8 @@ const toastService = injectService(SERVICE_TOKENS.TOAST_SERVICE) as any
// State
const showReceiveDialog = ref(false)
const showSendDialog = ref(false)
const showQRScanner = ref(false)
const scannedDestination = ref<string>('')
const selectedTab = ref('transactions')
const defaultQrCode = ref<string | null>(null)
const isGeneratingQR = ref(false)
@ -144,6 +148,26 @@ function handleQRClick() {
const encodedLNURL = encodeLNURL(firstPayLink.value.lnurl)
copyToClipboard(encodedLNURL, 'qr-lnurl')
}
// QR Scanner functions
function closeQRScanner() {
showQRScanner.value = false
}
function handleQRScanResult(result: string) {
// Clean up the scanned result by removing lightning: prefix if present
let cleanedResult = result
if (result.toLowerCase().startsWith('lightning:')) {
cleanedResult = result.substring(10) // Remove "lightning:" prefix
}
// Store the scanned result and close QR scanner
scannedDestination.value = cleanedResult
closeQRScanner()
// Open send dialog with the scanned result
showSendDialog.value = true
toastService?.success('QR code scanned successfully!')
}
// Initialize on mount
@ -211,6 +235,14 @@ onMounted(async () => {
<Send class="h-5 w-5" />
Send
</Button>
<Button
variant="outline"
@click="showQRScanner = true"
class="h-12 w-12 p-0"
title="Scan QR Code"
>
<ScanLine class="h-5 w-5" />
</Button>
</div>
</div>
</CardContent>
@ -517,10 +549,34 @@ onMounted(async () => {
@update:open="showReceiveDialog = $event"
/>
<SendDialog
<SendDialog
v-if="showSendDialog"
:open="showSendDialog"
@update:open="showSendDialog = $event"
:open="showSendDialog"
:initial-destination="scannedDestination"
@update:open="(open) => {
showSendDialog = open
if (!open) scannedDestination = ''
}"
/>
<!-- QR Scanner Dialog -->
<Dialog :open="showQRScanner" @update:open="showQRScanner = $event">
<DialogContent class="sm:max-w-lg">
<DialogHeader>
<DialogTitle class="flex items-center gap-2">
<ScanLine class="h-5 w-5" />
Scan QR Code
</DialogTitle>
<DialogDescription>
Point your camera at a Lightning invoice or payment QR code
</DialogDescription>
</DialogHeader>
<QRScanner
@result="handleQRScanResult"
@close="closeQRScanner"
/>
</DialogContent>
</Dialog>
</div>
</template>