fix(wallet): gate lightning on node STATE, gate send too, add a shared CopyButton
Three defects from testing the previous commit on archi-dev-box: 1. The gate keyed on `id in packages`, which is not "installed and usable" — package-data carries an entry for a Lightning app that is known but not running. On a box with no lnd container at all the gate passed and the raw error came through as "Operation failed. Check server logs for details." Now keyed on PackageState.Running. 2. Because installed-but-stopped is a real and different situation, the modal has two modes: absent offers the install choices, stopped says the node isn't running and offers "Open My Apps". Neither dead-ends in an error. 3. Lightning SEND let you walk all the way to confirm-send with no node. The gate now runs in review(), before the confirm step — failing at submit after a review screen is the defect, not a smaller version of it. Also adds CopyButton, the start of one consistent copy affordance: icon + label, an emerald tick held 1.6s, a fixed box so the width never jumps, and a document.execCommand fallback so copy still works over plain http on a LAN IP (navigator.clipboard rejects on insecure origins, which is how a lot of nodes are reached). Converted the wallet's own copies — the lightning invoice the user reported, plus the on-chain/Ark addresses and the payment hash/txid. 20 of 25 copy sites across 15 other files still use ad-hoc markup; converting them is mechanical but was not attempted here rather than half-done. Verified: 5 gate tests; npm run build clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
90ce4bcc46
commit
fa26c5fc56
@@ -25,20 +25,14 @@
|
||||
<p class="text-xs text-white/50 mb-1">Payment hash</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<p class="flex-1 text-xs font-mono text-white/80 break-all">{{ successInfo.hash }}</p>
|
||||
<button
|
||||
class="shrink-0 px-2.5 py-1.5 rounded-lg text-xs glass-button"
|
||||
@click="copyDetail(successInfo.hash)"
|
||||
>{{ copiedDetail === successInfo.hash ? 'Copied!' : 'Copy' }}</button>
|
||||
<CopyButton class="shrink-0" :value="successInfo.hash" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="successInfo.txid">
|
||||
<p class="text-xs text-white/50 mb-1">Transaction ID</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<p class="flex-1 text-xs font-mono text-white/80 break-all">{{ successInfo.txid }}</p>
|
||||
<button
|
||||
class="shrink-0 px-2.5 py-1.5 rounded-lg text-xs glass-button"
|
||||
@click="copyDetail(successInfo.txid)"
|
||||
>{{ copiedDetail === successInfo.txid ? 'Copied!' : 'Copy' }}</button>
|
||||
<CopyButton class="shrink-0" :value="successInfo.txid" />
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="successInfo.note" class="text-xs text-white/60">{{ successInfo.note }}</p>
|
||||
@@ -258,10 +252,13 @@
|
||||
import { ref, computed, watch, nextTick } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { rpcClient } from '@/api/rpc-client'
|
||||
import { useLightningRequired } from '@/composables/useLightningRequired'
|
||||
import BaseModal from '@/components/BaseModal.vue'
|
||||
import CopyButton from '@/components/CopyButton.vue'
|
||||
import ScreensaverRing from '@/components/ScreensaverRing.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const lightning = useLightningRequired()
|
||||
|
||||
const props = defineProps<{ show: boolean }>()
|
||||
const emit = defineEmits<{ close: []; sent: []; scan: [] }>()
|
||||
@@ -321,15 +318,6 @@ const successInfo = ref<{
|
||||
txid?: string
|
||||
note?: string
|
||||
} | null>(null)
|
||||
const copiedDetail = ref('')
|
||||
|
||||
function copyDetail(text: string) {
|
||||
navigator.clipboard.writeText(text).catch(() => {})
|
||||
copiedDetail.value = text
|
||||
setTimeout(() => {
|
||||
if (copiedDetail.value === text) copiedDetail.value = ''
|
||||
}, 1500)
|
||||
}
|
||||
const ecashToken = ref('')
|
||||
|
||||
// "Send all funds" — sweeps the whole on-chain balance (explicit on-chain tab only)
|
||||
@@ -530,6 +518,9 @@ function review() {
|
||||
const method = effectiveMethod.value
|
||||
const d = dest.value.trim()
|
||||
if (method === 'lightning') {
|
||||
// Gate BEFORE the confirm step, not at submit: walking a user through
|
||||
// review-and-confirm only to fail on a missing node is the defect.
|
||||
if (!lightning.requireLightningNode()) return
|
||||
if (!d) { error.value = t('web5.pasteInvoice'); return }
|
||||
invoiceAmountSats.value = parseBolt11AmountSats(d)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user