diff --git a/lamassu-next/apps/machine/src/views/CashInView.vue b/lamassu-next/apps/machine/src/views/CashInView.vue index b787e2b..e71ac70 100644 --- a/lamassu-next/apps/machine/src/views/CashInView.vue +++ b/lamassu-next/apps/machine/src/views/CashInView.vue @@ -22,29 +22,60 @@ const invoiceInput = ref('') // Copy state for ndebit URI const copied = ref(false) -// Tab state for QR display (ndebit vs LNURL-withdraw) -const activeTab = ref<'ndebit' | 'lnurl'>('ndebit') +// QR display mode: unified (default), lnurl-only, or clink-only +const qrMode = ref<'unified' | 'lnurl' | 'clink'>('unified') const lnurlWithdraw = ref(null) const isGeneratingLnurl = ref(false) -// Switch to LNURL tab and generate LNURL-withdraw if needed -async function switchToLnurl() { - activeTab.value = 'lnurl' - if (!lnurlWithdraw.value && !isGeneratingLnurl.value) { - isGeneratingLnurl.value = true - try { - lnurlWithdraw.value = await atmStore.generateLnurlWithdraw() - } catch (err) { - console.error('[CashIn] Failed to generate LNURL-withdraw:', err) - } finally { - isGeneratingLnurl.value = false +// Generate LNURL-withdraw when entering displayingQR state +watch( + () => atmStore.nestedState, + async (state) => { + if (state === 'displayingQR' && !lnurlWithdraw.value && !isGeneratingLnurl.value) { + isGeneratingLnurl.value = true + try { + lnurlWithdraw.value = await atmStore.generateLnurlWithdraw() + } catch (err) { + console.error('[CashIn] Failed to generate LNURL-withdraw:', err) + } finally { + isGeneratingLnurl.value = false + } } - } -} + }, + { immediate: true } +) -// Copy ndebit URI to clipboard -async function copyNdebit() { - const uri = atmStore.context?.ndebitUri +// Compute the unified QR value (lightning + clink on separate lines) +const unifiedQrValue = computed(() => { + const ndebit = atmStore.context?.ndebitUri + const lnurl = lnurlWithdraw.value + + if (lnurl && ndebit) { + // Unified: lightning scheme first (more universal), then clink + return `lightning:${lnurl}\n${ndebit}` + } else if (lnurl) { + return `lightning:${lnurl}` + } else if (ndebit) { + return ndebit + } + return null +}) + +// Get the appropriate QR value based on mode +const currentQrValue = computed(() => { + switch (qrMode.value) { + case 'unified': + return unifiedQrValue.value + case 'lnurl': + return lnurlWithdraw.value ? `lightning:${lnurlWithdraw.value}` : null + case 'clink': + return atmStore.context?.ndebitUri || null + } +}) + +// Copy current QR value to clipboard +async function copyQrValue() { + const uri = currentQrValue.value if (!uri) return try { @@ -223,94 +254,103 @@ const isProcessing = computed(() => atmStore.isPayingInvoice || atmStore.isReque - - - - Scan to Receive Sats - - - {{ formatSats(context.satsAmount) }} sats - - - -
- - -
-
- - -
- -

- Scan with Shock Wallet or compatible CLINK wallet + + + + +

+

Withdraw

+

+ {{ formatSats(context?.satsAmount || 0) }} sats

- -
-
- - +

+ ${{ ((context?.fiatAmount || 0) / 100).toFixed(2) }} +

+
+ + +
+

Scan with

+
+ + + +
+
+ + +
+
+ +
+ +
+
+

Generating...

+
+ +
+
+ ⚡ +
-

- Or copy and paste into your wallet -

- -
- - -
-

Failed to generate LNURL

-
-

- Scan with any Lightning wallet (Phoenix, Zeus, Wallet of Satoshi, etc.) + +

+

+ {{ + qrMode === 'unified' + ? 'Universal' + : qrMode === 'lnurl' + ? 'LNURL-withdraw' + : 'CLINK ndebit' + }}

+
+ + {{ currentQrValue.split('\n')[0].slice(0, 32) }}... + + +
- - - -

How it works:

-
    -
  1. 1. Scan the QR code with your CLINK-compatible wallet
  2. -
  3. - 2. Your wallet creates an invoice for - {{ formatSats(context?.satsAmount || 0) }} sats -
  4. -
  5. 3. Confirm the claim in your wallet
  6. -
  7. 4. Receive your sats instantly!
  8. -
-
    -
  1. 1. Scan the QR code with any Lightning wallet
  2. -
  3. - 2. Your wallet shows a withdrawal for - {{ formatSats(context?.satsAmount || 0) }} sats -
  4. -
  5. 3. Confirm the withdrawal in your wallet
  6. -
  7. 4. Sats arrive in your wallet!
  8. -
-
-
-