feat: add lud17 urls to qr / copy (#89)

* feat: add lud17 urls to qr / copy
This commit is contained in:
dni ⚡ 2025-07-23 11:32:13 +02:00 committed by GitHub
commit 1455afa219
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 88 additions and 14 deletions

View file

@ -27,6 +27,9 @@ window.app = Vue.createApp({
}, },
data() { data() {
return { return {
tab: 'bech32',
url: window.location.origin + '/lnurlp/api/v1/lnurl/',
lnurl: '',
settings: [ settings: [
{ {
type: 'str', type: 'str',
@ -100,6 +103,13 @@ window.app = Vue.createApp({
} }
}, },
methods: { methods: {
setBech32() {
const url =
window.location.origin + '/lnurlp/' + this.qrCodeDialog.data.id
const bytes = new TextEncoder().encode(url)
const bech32 = NostrTools.nip19.encodeBytes('lnurl', bytes)
this.lnurl = `lightning:${bech32.toUpperCase()}`
},
getPayLinks() { getPayLinks() {
LNbits.api LNbits.api
.request( .request(
@ -144,6 +154,7 @@ window.app = Vue.createApp({
print_url: link.print_url, print_url: link.print_url,
username: link.username username: link.username
} }
this.setBech32()
this.qrCodeDialog.show = true this.qrCodeDialog.show = true
}, },
openUpdateDialog(linkId) { openUpdateDialog(linkId) {
@ -275,12 +286,23 @@ window.app = Vue.createApp({
} }
} }
}, },
watch: {
tab(value) {
if (value == 'bech32') {
this.setBech32()
} else if (value == 'lud17') {
const url =
window.location.origin + '/lnurlp/' + this.qrCodeDialog.data.id
this.lnurl = url.replace('https://', 'lnurlp://')
}
}
},
created() { created() {
if (this.g.user.wallets?.length) { if (this.g.user.wallets?.length) {
this.getPayLinks() this.getPayLinks()
} }
LNbits.api LNbits.api
.request('GET', '/lnurlp/api/v1/currencies') .request('GET', '/api/v1/currencies')
.then(response => { .then(response => {
this.currencies = ['satoshis', ...response.data] this.currencies = ['satoshis', ...response.data]
}) })

View file

@ -2,21 +2,36 @@
<div class="row q-col-gutter-md justify-center"> <div class="row q-col-gutter-md justify-center">
<div class="col-12 col-sm-6 col-md-5 col-lg-4"> <div class="col-12 col-sm-6 col-md-5 col-lg-4">
<q-card class="q-pa-lg"> <q-card class="q-pa-lg">
<q-card-section>
<q-tabs
v-model="tab"
dense
class="text-grey"
active-color="primary"
indicator-color="primary"
align="justify"
narrow-indicator
inline-label
>
<q-tab name="bech32" icon="qr_code" label="bech32"></q-tab>
<q-tab name="lud17" icon="link" label="url (lud17)"></q-tab>
</q-tabs>
</q-card-section>
<q-card-section class="q-pa-none"> <q-card-section class="q-pa-none">
<div class="text-center"> <div class="text-center">
<a class="text-secondary" href="lightning:{{ lnurl }}"> <a class="text-secondary" href="lnurl">
<lnbits-qrcode value="lightning:{{ lnurl }}"></lnbits-qrcode> <lnbits-qrcode :value="lnurl"></lnbits-qrcode>
</a> </a>
</div> </div>
<div class="row q-mt-lg q-gutter-sm"> <div class="row q-mt-lg q-gutter-sm">
<q-btn outline color="grey" @click="copyText('{{ lnurl }}')" <q-btn outline color="grey" @click="copyText(lnurl)"
>Copy LNURL</q-btn >Copy LNURL</q-btn
> >
<q-btn <q-btn
outline outline
color="grey" color="grey"
icon="nfc" icon="nfc"
@click="writeNfcTag(' {{ lnurl }} ')" @click="writeNfcTag(lnurl)"
:disable="nfcTagWriting" :disable="nfcTagWriting"
></q-btn> ></q-btn>
</div> </div>
@ -40,7 +55,33 @@
<script> <script>
window.app = Vue.createApp({ window.app = Vue.createApp({
el: '#vue', el: '#vue',
mixins: [window.windowMixin] mixins: [window.windowMixin],
data() {
return {
tab: 'bech32',
url: window.location.origin + '/lnurlp/{{ link_id }}',
lnurl: ''
}
},
methods: {
setBech32() {
const bytes = new TextEncoder().encode(this.url)
const bech32 = NostrTools.nip19.encodeBytes('lnurl', bytes)
this.lnurl = `lightning:${bech32.toUpperCase()}`
}
},
watch: {
tab(value) {
if (value == 'bech32') {
this.setBech32()
} else if (value == 'lud17') {
this.lnurl = this.url.replace('https://', 'lnurlp://')
}
}
},
created() {
this.setBech32()
}
}) })
</script> </script>
{% endblock %} {% endblock %}

View file

@ -357,9 +357,22 @@
<q-dialog v-model="qrCodeDialog.show" position="top"> <q-dialog v-model="qrCodeDialog.show" position="top">
<q-card v-if="qrCodeDialog.data" class="q-pa-lg lnbits__dialog-card"> <q-card v-if="qrCodeDialog.data" class="q-pa-lg lnbits__dialog-card">
<lnbits-qrcode <q-card-section>
:value="'lightning:' + qrCodeDialog.data.lnurl" <q-tabs
></lnbits-qrcode> v-model="tab"
dense
class="text-grey"
active-color="primary"
indicator-color="primary"
align="justify"
narrow-indicator
inline-label
>
<q-tab name="bech32" icon="qr_code" label="bech32"></q-tab>
<q-tab name="lud17" icon="link" label="url (lud17)"></q-tab>
</q-tabs>
</q-card-section>
<lnbits-qrcode :value="lnurl"></lnbits-qrcode>
<p style="word-break: break-all"> <p style="word-break: break-all">
<strong>ID:</strong> <span v-text="qrCodeDialog.data.id"></span><br /> <strong>ID:</strong> <span v-text="qrCodeDialog.data.id"></span><br />
<strong>Amount:</strong> <span v-text="qrCodeDialog.data.amount"></span <strong>Amount:</strong> <span v-text="qrCodeDialog.data.amount"></span
@ -392,7 +405,7 @@
<q-btn <q-btn
outline outline
color="grey" color="grey"
@click="copyText(qrCodeDialog.data.lnurl, 'LNURL copied to clipboard!')" @click="copyText(lnurl, 'LNURL copied to clipboard!')"
class="q-ml-sm" class="q-ml-sm"
>Copy LNURL</q-btn >Copy LNURL</q-btn
> >
@ -407,7 +420,7 @@
outline outline
color="grey" color="grey"
icon="nfc" icon="nfc"
@click="writeNfcTag(qrCodeDialog.data.lnurl)" @click="writeNfcTag(lnurl)"
:disable="nfcTagWriting" :disable="nfcTagWriting"
><q-tooltip>Write to NFC</q-tooltip> ><q-tooltip>Write to NFC</q-tooltip>
</q-btn> </q-btn>

View file

@ -30,7 +30,7 @@ async def display(request: Request, link_id):
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist." status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist."
) )
ctx = {"request": request, "lnurl": link.lnurl(req=request)} ctx = {"request": request, "link_id": link.id}
return lnurlp_renderer().TemplateResponse("lnurlp/display.html", ctx) return lnurlp_renderer().TemplateResponse("lnurlp/display.html", ctx)

View file

@ -132,13 +132,11 @@ async def api_lnurl_callback(
@lnurlp_lnurl_router.get( @lnurlp_lnurl_router.get(
"/api/v1/lnurl/{link_id}", # Backwards compatibility for old LNURLs / QR codes "/api/v1/lnurl/{link_id}", # Backwards compatibility for old LNURLs / QR codes
status_code=HTTPStatus.OK,
name="lnurlp.api_lnurl_response.deprecated", name="lnurlp.api_lnurl_response.deprecated",
deprecated=True, deprecated=True,
) )
@lnurlp_lnurl_router.get( @lnurlp_lnurl_router.get(
"/{link_id}", "/{link_id}",
status_code=HTTPStatus.OK,
name="lnurlp.api_lnurl_response", name="lnurlp.api_lnurl_response",
) )
async def api_lnurl_response( async def api_lnurl_response(