lnurl-pay and lnurl-withdraw UI.
This commit is contained in:
parent
7a5159f293
commit
3cd15c40fc
|
@ -14,12 +14,8 @@ function generateChart(canvas, payments) {
|
|||
}
|
||||
|
||||
_.each(
|
||||
payments
|
||||
.filter(p => !p.pending)
|
||||
.sort(function (a, b) {
|
||||
return a.time - b.time
|
||||
}),
|
||||
function (tx) {
|
||||
payments.filter(p => !p.pending).sort((a, b) => a.time - b.time),
|
||||
tx => {
|
||||
txs.push({
|
||||
hour: Quasar.utils.date.formatDate(tx.date, 'YYYY-MM-DDTHH:00'),
|
||||
sat: tx.sat
|
||||
|
@ -27,19 +23,15 @@ function generateChart(canvas, payments) {
|
|||
}
|
||||
)
|
||||
|
||||
_.each(_.groupBy(txs, 'hour'), function (value, day) {
|
||||
_.each(_.groupBy(txs, 'hour'), (value, day) => {
|
||||
var income = _.reduce(
|
||||
value,
|
||||
function (memo, tx) {
|
||||
return tx.sat >= 0 ? memo + tx.sat : memo
|
||||
},
|
||||
(memo, tx) => (tx.sat >= 0 ? memo + tx.sat : memo),
|
||||
0
|
||||
)
|
||||
var outcome = _.reduce(
|
||||
value,
|
||||
function (memo, tx) {
|
||||
return tx.sat < 0 ? memo + Math.abs(tx.sat) : memo
|
||||
},
|
||||
(memo, tx) => (tx.sat < 0 ? memo + Math.abs(tx.sat) : memo),
|
||||
0
|
||||
)
|
||||
n = n + income - outcome
|
||||
|
@ -124,23 +116,27 @@ new Vue({
|
|||
show: false,
|
||||
status: 'pending',
|
||||
paymentReq: null,
|
||||
minMax: [0, 2100000000000000],
|
||||
lnurl: null,
|
||||
data: {
|
||||
amount: null,
|
||||
memo: ''
|
||||
}
|
||||
},
|
||||
send: {
|
||||
parse: {
|
||||
show: false,
|
||||
invoice: null,
|
||||
lnurl: {},
|
||||
lnurlpay: null,
|
||||
data: {
|
||||
request: ''
|
||||
request: '',
|
||||
amount: 0
|
||||
},
|
||||
paymentChecker: null,
|
||||
camera: {
|
||||
show: false,
|
||||
camera: 'auto'
|
||||
}
|
||||
},
|
||||
theCamera: {
|
||||
show: false,
|
||||
camera: 'auto'
|
||||
},
|
||||
payments: [],
|
||||
paymentsTable: {
|
||||
columns: [
|
||||
|
@ -197,8 +193,8 @@ new Vue({
|
|||
return LNbits.utils.search(this.payments, q)
|
||||
},
|
||||
canPay: function () {
|
||||
if (!this.send.invoice) return false
|
||||
return this.send.invoice.sat <= this.balance
|
||||
if (!this.parse.invoice) return false
|
||||
return this.parse.invoice.sat <= this.balance
|
||||
},
|
||||
pendingPaymentsExist: function () {
|
||||
return this.payments
|
||||
|
@ -206,56 +202,55 @@ new Vue({
|
|||
: false
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
msatoshiFormat: function (value) {
|
||||
return LNbits.utils.formatSat(value / 1000)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeCamera: function () {
|
||||
this.theCamera.show = false
|
||||
this.parse.camera.show = false
|
||||
},
|
||||
showCamera: function () {
|
||||
this.theCamera.show = true
|
||||
this.parse.camera.show = true
|
||||
},
|
||||
showChart: function () {
|
||||
this.paymentsChart.show = true
|
||||
this.$nextTick(function () {
|
||||
this.$nextTick(() => {
|
||||
generateChart(this.$refs.canvas, this.payments)
|
||||
})
|
||||
},
|
||||
showReceiveDialog: function () {
|
||||
this.receive = {
|
||||
show: true,
|
||||
status: 'pending',
|
||||
paymentReq: null,
|
||||
data: {
|
||||
amount: null,
|
||||
memo: ''
|
||||
},
|
||||
paymentChecker: null
|
||||
}
|
||||
this.receive.show = true
|
||||
this.receive.status = 'pending'
|
||||
this.receive.paymentReq = null
|
||||
this.receive.data.amount = null
|
||||
this.receive.data.memo = null
|
||||
this.receive.paymentChecker = null
|
||||
this.receive.minMax = [0, 2100000000000000]
|
||||
this.receive.lnurl = null
|
||||
},
|
||||
showSendDialog: function () {
|
||||
this.send = {
|
||||
show: true,
|
||||
invoice: null,
|
||||
lnurl: {},
|
||||
data: {
|
||||
request: ''
|
||||
},
|
||||
paymentChecker: null
|
||||
}
|
||||
showParseDialog: function () {
|
||||
this.parse.show = true
|
||||
this.parse.invoice = null
|
||||
this.parse.lnurlpay = null
|
||||
this.parse.data.request = ''
|
||||
this.parse.data.paymentChecker = null
|
||||
this.parse.camera.show = false
|
||||
},
|
||||
closeReceiveDialog: function () {
|
||||
var checker = this.receive.paymentChecker
|
||||
setTimeout(function () {
|
||||
setTimeout(() => {
|
||||
clearInterval(checker)
|
||||
}, 10000)
|
||||
},
|
||||
closeSendDialog: function () {
|
||||
var checker = this.send.paymentChecker
|
||||
setTimeout(function () {
|
||||
closeParseDialog: function () {
|
||||
var checker = this.parse.paymentChecker
|
||||
setTimeout(() => {
|
||||
clearInterval(checker)
|
||||
}, 1000)
|
||||
},
|
||||
createInvoice: function () {
|
||||
var self = this
|
||||
this.receive.status = 'loading'
|
||||
LNbits.api
|
||||
.createInvoice(
|
||||
|
@ -263,59 +258,96 @@ new Vue({
|
|||
this.receive.data.amount,
|
||||
this.receive.data.memo
|
||||
)
|
||||
.then(function (response) {
|
||||
self.receive.status = 'success'
|
||||
self.receive.paymentReq = response.data.payment_request
|
||||
.then(response => {
|
||||
this.receive.status = 'success'
|
||||
this.receive.paymentReq = response.data.payment_request
|
||||
|
||||
self.receive.paymentChecker = setInterval(function () {
|
||||
if (this.receive.lnurl) {
|
||||
// send invoice to lnurl callback
|
||||
console.log('sending', this.receive.lnurl)
|
||||
LNbits.api.sendInvoiceToLnurlWithdraw(this.receive.paymentReq)
|
||||
}
|
||||
|
||||
this.receive.paymentChecker = setInterval(() => {
|
||||
LNbits.api
|
||||
.getPayment(self.g.wallet, response.data.payment_hash)
|
||||
.then(function (response) {
|
||||
.getPayment(this.g.wallet, response.data.payment_hash)
|
||||
.then(response => {
|
||||
if (response.data.paid) {
|
||||
self.fetchPayments()
|
||||
self.receive.show = false
|
||||
clearInterval(self.receive.paymentChecker)
|
||||
this.fetchPayments()
|
||||
this.receive.show = false
|
||||
clearInterval(this.receive.paymentChecker)
|
||||
}
|
||||
})
|
||||
}, 2000)
|
||||
})
|
||||
.catch(function (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
self.receive.status = 'pending'
|
||||
.catch(err => {
|
||||
LNbits.utils.notifyApiError(err)
|
||||
this.receive.status = 'pending'
|
||||
})
|
||||
},
|
||||
decodeQR: function (res) {
|
||||
this.send.data.request = res
|
||||
this.parse.data.request = res
|
||||
this.decodeRequest()
|
||||
this.sendCamera.show = false
|
||||
this.parse.camera.show = false
|
||||
},
|
||||
decodeRequest: function () {
|
||||
if (this.send.data.request.startsWith('lightning:')) {
|
||||
this.send.data.request = this.send.data.request.slice(10)
|
||||
this.parse.show = true
|
||||
|
||||
if (this.parse.data.request.startsWith('lightning:')) {
|
||||
this.parse.data.request = this.parse.data.request.slice(10)
|
||||
}
|
||||
if (this.send.data.request.startsWith('lnurl:')) {
|
||||
this.send.data.request = this.send.data.request.slice(6)
|
||||
if (this.parse.data.request.startsWith('lnurl:')) {
|
||||
this.parse.data.request = this.parse.data.request.slice(6)
|
||||
}
|
||||
|
||||
if (this.send.data.request.toLowerCase().startsWith('lnurl1')) {
|
||||
if (this.parse.data.request.toLowerCase().startsWith('lnurl1')) {
|
||||
LNbits.api
|
||||
.request(
|
||||
'GET',
|
||||
'/api/v1/lnurlscan/' + this.send.data.request,
|
||||
'/api/v1/lnurlscan/' + this.parse.data.request,
|
||||
this.g.user.wallets[0].adminkey
|
||||
)
|
||||
.then(function (response) {
|
||||
this.send.lnurl[response.kind] = Object.freeze(response)
|
||||
.catch(err => {
|
||||
LNbits.utils.notifyApiError(err)
|
||||
})
|
||||
.catch(function (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
.then(response => {
|
||||
let data = response.data
|
||||
|
||||
if (data.status === 'ERROR') {
|
||||
Quasar.plugins.Notify.create({
|
||||
timeout: 5000,
|
||||
type: 'warning',
|
||||
message: data.reason,
|
||||
caption: `${data.domain} returned an error to the lnurl call.`,
|
||||
icon: null
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (data.kind === 'pay') {
|
||||
this.parse.lnurlpay = Object.freeze(data)
|
||||
this.parse.data.amount = data.minSendable / 1000
|
||||
} else if (data.kind === 'withdraw') {
|
||||
this.parse.show = false
|
||||
this.receive.show = true
|
||||
this.receive.status = 'pending'
|
||||
this.receive.data.amount = data.maxWithdrawable
|
||||
this.receive.data.memo = data.defaultDescription
|
||||
this.receive.minMax = [data.minWithdrawable, data.maxWithdrawable]
|
||||
this.receive.lnurl = {
|
||||
domain: data.domain,
|
||||
callback: data.callback,
|
||||
k1: data.k1,
|
||||
fixed: data.fixed
|
||||
}
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
let invoice
|
||||
try {
|
||||
invoice = decode(this.send.data.bolt11)
|
||||
invoice = decode(this.parse.data.bolt11)
|
||||
} catch (error) {
|
||||
this.$q.notify({
|
||||
timeout: 3000,
|
||||
|
@ -324,6 +356,7 @@ new Vue({
|
|||
caption: '400 BAD REQUEST',
|
||||
icon: null
|
||||
})
|
||||
this.parse.show = false
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -333,7 +366,7 @@ new Vue({
|
|||
fsat: LNbits.utils.formatSat(invoice.human_readable_part.amount / 1000)
|
||||
}
|
||||
|
||||
_.each(invoice.data.tags, function (tag) {
|
||||
_.each(invoice.data.tags, tag => {
|
||||
if (_.isObject(tag) && _.has(tag, 'description')) {
|
||||
if (tag.description === 'payment_hash') {
|
||||
cleanInvoice.hash = tag.value
|
||||
|
@ -352,11 +385,9 @@ new Vue({
|
|||
}
|
||||
})
|
||||
|
||||
this.send.invoice = Object.freeze(cleanInvoice)
|
||||
this.parse.invoice = Object.freeze(cleanInvoice)
|
||||
},
|
||||
payInvoice: function () {
|
||||
var self = this
|
||||
|
||||
let dismissPaymentMsg = this.$q.notify({
|
||||
timeout: 0,
|
||||
message: 'Processing payment...',
|
||||
|
@ -364,55 +395,80 @@ new Vue({
|
|||
})
|
||||
|
||||
LNbits.api
|
||||
.payInvoice(this.g.wallet, this.send.data.bolt11)
|
||||
.then(function (response) {
|
||||
self.send.paymentChecker = setInterval(function () {
|
||||
.payInvoice(this.g.wallet, this.parse.data.bolt11)
|
||||
.then(response => {
|
||||
this.parse.paymentChecker = setInterval(() => {
|
||||
LNbits.api
|
||||
.getPayment(self.g.wallet, response.data.payment_hash)
|
||||
.then(function (res) {
|
||||
.getPayment(this.g.wallet, response.data.payment_hash)
|
||||
.then(res => {
|
||||
if (res.data.paid) {
|
||||
self.send.show = false
|
||||
clearInterval(self.send.paymentChecker)
|
||||
this.parse.show = false
|
||||
clearInterval(this.parse.paymentChecker)
|
||||
dismissPaymentMsg()
|
||||
self.fetchPayments()
|
||||
this.fetchPayments()
|
||||
}
|
||||
})
|
||||
}, 2000)
|
||||
})
|
||||
.catch(function (error) {
|
||||
.catch(err => {
|
||||
dismissPaymentMsg()
|
||||
LNbits.utils.notifyApiError(error)
|
||||
LNbits.utils.notifyApiError(err)
|
||||
})
|
||||
},
|
||||
payLnurl: function () {
|
||||
let dismissPaymentMsg = this.$q.notify({
|
||||
timeout: 0,
|
||||
message: 'Processing payment...',
|
||||
icon: null
|
||||
})
|
||||
|
||||
LNbits.api
|
||||
.payInvoice(this.g.wallet, this.parse.data.bolt11)
|
||||
.then(response => {
|
||||
this.parse.paymentChecker = setInterval(() => {
|
||||
LNbits.api
|
||||
.getPayment(this.g.wallet, response.data.payment_hash)
|
||||
.then(res => {
|
||||
if (res.data.paid) {
|
||||
this.parse.show = false
|
||||
clearInterval(this.parse.paymentChecker)
|
||||
dismissPaymentMsg()
|
||||
this.fetchPayments()
|
||||
}
|
||||
})
|
||||
}, 2000)
|
||||
})
|
||||
.catch(err => {
|
||||
dismissPaymentMsg()
|
||||
LNbits.utils.notifyApiError(err)
|
||||
})
|
||||
},
|
||||
deleteWallet: function (walletId, user) {
|
||||
LNbits.utils
|
||||
.confirmDialog('Are you sure you want to delete this wallet?')
|
||||
.onOk(function () {
|
||||
.onOk(() => {
|
||||
LNbits.href.deleteWallet(walletId, user)
|
||||
})
|
||||
},
|
||||
fetchPayments: function (checkPending) {
|
||||
var self = this
|
||||
|
||||
return LNbits.api
|
||||
.getPayments(this.g.wallet, checkPending)
|
||||
.then(function (response) {
|
||||
self.payments = response.data
|
||||
.map(function (obj) {
|
||||
.then(response => {
|
||||
this.payments = response.data
|
||||
.map(obj => {
|
||||
return LNbits.map.payment(obj)
|
||||
})
|
||||
.sort(function (a, b) {
|
||||
.sort((a, b) => {
|
||||
return b.time - a.time
|
||||
})
|
||||
})
|
||||
},
|
||||
fetchBalance: function () {
|
||||
var self = this
|
||||
LNbits.api.getWallet(self.g.wallet).then(function (response) {
|
||||
self.balance = Math.round(response.data.balance / 1000)
|
||||
LNbits.api.getWallet(this.g.wallet).then(response => {
|
||||
this.balance = Math.round(response.data.balance / 1000)
|
||||
EventHub.$emit('update-wallet-balance', [
|
||||
self.g.wallet.id,
|
||||
self.balance
|
||||
this.g.wallet.id,
|
||||
this.balance
|
||||
])
|
||||
})
|
||||
},
|
||||
|
@ -423,7 +479,7 @@ new Vue({
|
|||
icon: null
|
||||
})
|
||||
|
||||
this.fetchPayments(true).then(function () {
|
||||
this.fetchPayments(true).then(() => {
|
||||
dismissMsg()
|
||||
})
|
||||
},
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
unelevated
|
||||
color="deep-purple"
|
||||
class="full-width"
|
||||
@click="showSendDialog"
|
||||
@click="showParseDialog"
|
||||
>Paste Request</q-btn
|
||||
>
|
||||
</div>
|
||||
|
@ -249,18 +249,26 @@
|
|||
</q-card>
|
||||
</div>
|
||||
|
||||
<q-dialog v-model="receive.show" position="top" @hide="closeReceiveDialog">
|
||||
<q-dialog v-model="receive.show" @hide="closeReceiveDialog">
|
||||
{% raw %}
|
||||
<q-card
|
||||
v-if="!receive.paymentReq"
|
||||
class="q-pa-lg q-pt-xl lnbits__dialog-card"
|
||||
>
|
||||
<q-form @submit="createInvoice" class="q-gutter-md">
|
||||
<p v-if="receive.lnurl" class="text-h6 text-center q-my-none">
|
||||
<b>{{receive.lnurl.domain}}</b> is requesting an invoice:
|
||||
</p>
|
||||
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.number="receive.data.amount"
|
||||
type="number"
|
||||
label="Amount (sat) *"
|
||||
min="receive.minMax[0]"
|
||||
max="receive.minMax[1]"
|
||||
:readonly="receive.lnurl && receive.lnurl.fixed"
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
|
@ -275,8 +283,12 @@
|
|||
color="deep-purple"
|
||||
:disable="receive.data.amount == null || receive.data.amount <= 0"
|
||||
type="submit"
|
||||
>Create invoice</q-btn
|
||||
>
|
||||
<span v-if="receive.lnurl">
|
||||
Withdraw from {{receive.lnurl.domain}}
|
||||
</span>
|
||||
<span v-else> Create invoice </span>
|
||||
</q-btn>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
</div>
|
||||
<q-spinner
|
||||
|
@ -305,20 +317,79 @@
|
|||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Close</q-btn>
|
||||
</div>
|
||||
</q-card>
|
||||
{% endraw %}
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog v-model="send.show" position="top" @hide="closeSendDialog">
|
||||
<q-dialog v-model="parse.show" @hide="closeParseDialog">
|
||||
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
||||
<div v-if="!send.invoice">
|
||||
<div v-if="parse.invoice">
|
||||
{% raw %}
|
||||
<h6 class="q-my-none">{{ parse.invoice.fsat }} sat</h6>
|
||||
<q-separator class="q-my-sm"></q-separator>
|
||||
<p style="word-break: break-all">
|
||||
<strong>Description:</strong> {{ parse.invoice.description }}<br />
|
||||
<strong>Expire date:</strong> {{ parse.invoice.expireDate }}<br />
|
||||
<strong>Hash:</strong> {{ parse.invoice.hash }}
|
||||
</p>
|
||||
{% endraw %}
|
||||
<div v-if="canPay" class="row q-mt-lg">
|
||||
<q-btn unelevated color="deep-purple" @click="payInvoice">Pay</q-btn>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
</div>
|
||||
<div v-else class="row q-mt-lg">
|
||||
<q-btn unelevated disabled color="yellow" text-color="black"
|
||||
>Not enough funds!</q-btn
|
||||
>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="parse.lnurlpay">
|
||||
{% raw %}
|
||||
<q-form @submit="payLnurl" class="q-gutter-md">
|
||||
<p v-if="parse.lnurlpay.fixed" class="q-my-none text-h6">
|
||||
{{ parse.lnurlpay.maxSendable | msatoshiFormat }}
|
||||
</p>
|
||||
<p v-else class="q-my-none text-h6 text-center">
|
||||
<b>{{ parse.lnurlpay.domain }}</b> is requesting <br />
|
||||
between <b>{{ parse.lnurlpay.minSendable | msatoshiFormat }}</b> and
|
||||
<b>{{ parse.lnurlpay.maxSendable | msatoshiFormat }}</b> sat
|
||||
</p>
|
||||
<q-separator class="q-my-sm"></q-separator>
|
||||
<p class="text-justify text-italic">{{ parse.lnurlpay.description }}</p>
|
||||
<p v-if="parse.lnurlpay.image">
|
||||
<q-img :src="parse.lnurlpay.image" width="50%" />
|
||||
</p>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.number="parse.data.amount"
|
||||
type="number"
|
||||
label="Amount (sat) *"
|
||||
min="parse.lnurlpay.minSendable / 1000"
|
||||
max="parse.lnurlpay.maxSendable / 1000"
|
||||
:readonly="parse.lnurlpay.fixed"
|
||||
></q-input>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn unelevated color="deep-purple" type="submit"
|
||||
>Send satoshis</q-btn
|
||||
>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
|
||||
>Cancel</q-btn
|
||||
>
|
||||
</div>
|
||||
</q-form>
|
||||
{% endraw %}
|
||||
</div>
|
||||
<div v-else>
|
||||
<q-form
|
||||
v-if="!theCamera.show"
|
||||
@submit="decodeInvoice"
|
||||
v-if="!parse.camera.show"
|
||||
@submit="decodeRequest"
|
||||
class="q-gutter-md"
|
||||
>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="send.data.request"
|
||||
v-model.trim="parse.data.request"
|
||||
type="textarea"
|
||||
label="Paste an invoice, payment request or lnurl code *"
|
||||
>
|
||||
|
@ -327,7 +398,7 @@
|
|||
<q-btn
|
||||
unelevated
|
||||
color="deep-purple"
|
||||
:disable="send.data.request == ''"
|
||||
:disable="parse.data.request == ''"
|
||||
type="submit"
|
||||
>Read</q-btn
|
||||
>
|
||||
|
@ -344,62 +415,16 @@
|
|||
></qrcode-stream>
|
||||
</q-responsive>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn @click="closeCamera" flat color="grey" class="q-ml-auto"
|
||||
>Cancel</q-btn
|
||||
>
|
||||
<q-btn @click="closeCamera" flat color="grey" class="q-ml-auto">
|
||||
Cancel
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="send.lnurl.withdraw">
|
||||
{% raw %}
|
||||
<h6 class="q-my-none">{{ send.invoice.fsat }} sat</h6>
|
||||
<q-separator class="q-my-sm"></q-separator>
|
||||
<p style="word-break: break-all">
|
||||
<strong>Description:</strong> {{ send.invoice.description }}<br />
|
||||
<strong>Payment hash:</strong> {{ send.invoice.hash }}<br />
|
||||
<strong>Expire date:</strong> {{ send.invoice.expireDate }}
|
||||
</p>
|
||||
{% endraw %}
|
||||
<div v-if="canPay" class="row q-mt-lg">
|
||||
<q-btn unelevated color="deep-purple" @click="payInvoice"
|
||||
>Send satoshis</q-btn
|
||||
>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
</div>
|
||||
<div v-else class="row q-mt-lg">
|
||||
<q-btn unelevated disabled color="yellow" text-color="black"
|
||||
>Not enough funds!</q-btn
|
||||
>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
{% raw %}
|
||||
<h6 class="q-my-none">{{ send.invoice.fsat }} sat</h6>
|
||||
<q-separator class="q-my-sm"></q-separator>
|
||||
<p style="word-break: break-all">
|
||||
<strong>Description:</strong> {{ send.invoice.description }}<br />
|
||||
<strong>Expire date:</strong> {{ send.invoice.expireDate }}<br />
|
||||
<strong>Hash:</strong> {{ send.invoice.hash }}
|
||||
</p>
|
||||
{% endraw %}
|
||||
<div v-if="canPay" class="row q-mt-lg">
|
||||
<q-btn unelevated color="deep-purple" @click="payInvoice"
|
||||
>Send satoshis</q-btn
|
||||
>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
</div>
|
||||
<div v-else class="row q-mt-lg">
|
||||
<q-btn unelevated disabled color="yellow" text-color="black"
|
||||
>Not enough funds!</q-btn
|
||||
>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog v-model="theCamera.show" position="top">
|
||||
<q-dialog v-model="parse.camera.show">
|
||||
<q-card class="q-pa-lg q-pt-xl">
|
||||
<div class="text-center q-mb-lg">
|
||||
<qrcode-stream @decode="decodeQR" class="rounded-borders"></qrcode-stream>
|
||||
|
@ -412,7 +437,7 @@
|
|||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog v-model="paymentsChart.show" position="top">
|
||||
<q-dialog v-model="paymentsChart.show">
|
||||
<q-card class="q-pa-sm" style="width: 800px; max-width: unset">
|
||||
<q-card-section>
|
||||
<canvas ref="canvas" width="600" height="400"></canvas>
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
<<<<<<< HEAD
|
||||
import trio # type: ignore
|
||||
import json
|
||||
import lnurl
|
||||
import httpx
|
||||
import traceback
|
||||
from quart import g, jsonify, request, make_response
|
||||
=======
|
||||
import lnurl
|
||||
from quart import g, jsonify, request
|
||||
>>>>>>> da8fd9a... send/create buttons wip.
|
||||
from http import HTTPStatus
|
||||
from binascii import unhexlify
|
||||
from urllib.parse import urlparse
|
||||
from typing import Dict
|
||||
|
||||
from lnbits import bolt11
|
||||
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
|
||||
|
@ -137,7 +135,6 @@ async def api_payment(payment_hash):
|
|||
return jsonify({"paid": not payment.pending}), HTTPStatus.OK
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
@core_app.route("/api/v1/payments/sse", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
async def api_payments_sse():
|
||||
|
@ -190,8 +187,6 @@ async def api_payments_sse():
|
|||
)
|
||||
response.timeout = None
|
||||
return response
|
||||
=======
|
||||
return jsonify({"paid": False}), HTTPStatus.OK
|
||||
|
||||
|
||||
@core_app.route("/api/v1/lnurlscan/<code>", methods=["GET"])
|
||||
|
@ -206,20 +201,30 @@ async def api_lnurlscan(code: str):
|
|||
if url.is_login:
|
||||
return jsonify({"domain": domain, "kind": "auth", "error": "unsupported"})
|
||||
|
||||
data: lnurl.LnurlResponseModel = lnurl.get(url.url)
|
||||
if not data.ok:
|
||||
r = httpx.get(url.url)
|
||||
if r.is_error:
|
||||
return jsonify({"domain": domain, "error": "failed to get parameters"})
|
||||
|
||||
try:
|
||||
jdata = json.loads(r.text)
|
||||
data: lnurl.LnurlResponseModel = lnurl.LnurlResponse.from_dict(jdata)
|
||||
except (json.decoder.JSONDecodeError, lnurl.exceptions.LnurlResponseException):
|
||||
return jsonify({"domain": domain, "error": f"got invalid response '{r.text[:200]}'"})
|
||||
|
||||
if type(data) is lnurl.LnurlChannelResponse:
|
||||
return jsonify({"domain": domain, "kind": "channel", "error": "unsupported"})
|
||||
|
||||
params = data.dict()
|
||||
params: Dict = data.dict()
|
||||
if type(data) is lnurl.LnurlWithdrawResponse:
|
||||
params.update(kind="withdraw", fixed=data.min_withdrawable == data.max_withdrawable)
|
||||
|
||||
if type(data) is lnurl.LnurlPayResponse:
|
||||
params.update(kind="pay", fixed=data.min_sendable == data.max_sendable)
|
||||
params.update(description=data.metadata.text)
|
||||
if data.metadata.images:
|
||||
image = min(data.metadata.images, key=lambda image: len(image[1]))
|
||||
data_uri = "data:" + image[0] + "," + image[1]
|
||||
params.update(image=data_uri)
|
||||
|
||||
params.update(domain=domain)
|
||||
return jsonify(params)
|
||||
>>>>>>> da8fd9a... send/create buttons wip.
|
||||
|
|
Loading…
Reference in New Issue
Block a user