add a dialog with payment details for each payment.

for outgoing payments this needs a preimage to be good,
but we don't have it yet because we don't get it from
backends.
This commit is contained in:
fiatjaf
2020-09-02 19:19:19 -03:00
parent 197af922d0
commit ce28db76c9
5 changed files with 172 additions and 105 deletions
+49 -55
View File
@@ -14,10 +14,10 @@ function generateChart(canvas, payments) {
}
_.each(
payments.slice(0).sort(function(a, b) {
payments.slice(0).sort(function (a, b) {
return a.time - b.time
}),
function(tx) {
function (tx) {
txs.push({
hour: Quasar.utils.date.formatDate(tx.date, 'YYYY-MM-DDTHH:00'),
sat: tx.sat
@@ -25,17 +25,17 @@ function generateChart(canvas, payments) {
}
)
_.each(_.groupBy(txs, 'hour'), function(value, day) {
_.each(_.groupBy(txs, 'hour'), function (value, day) {
var income = _.reduce(
value,
function(memo, tx) {
function (memo, tx) {
return tx.sat >= 0 ? memo + tx.sat : memo
},
0
)
var outcome = _.reduce(
value,
function(memo, tx) {
function (memo, tx) {
return tx.sat < 0 ? memo + Math.abs(tx.sat) : memo
},
0
@@ -67,20 +67,14 @@ function generateChart(canvas, payments) {
type: 'bar',
label: 'in',
barPercentage: 0.75,
backgroundColor: window
.Color('rgb(76,175,80)')
.alpha(0.5)
.rgbString() // green
backgroundColor: window.Color('rgb(76,175,80)').alpha(0.5).rgbString() // green
},
{
data: data.outcome,
type: 'bar',
label: 'out',
barPercentage: 0.75,
backgroundColor: window
.Color('rgb(233,30,99)')
.alpha(0.5)
.rgbString() // pink
backgroundColor: window.Color('rgb(233,30,99)').alpha(0.5).rgbString() // pink
}
]
},
@@ -121,7 +115,7 @@ function generateChart(canvas, payments) {
new Vue({
el: '#vue',
mixins: [windowMixin],
data: function() {
data: function () {
return {
user: LNbits.map.user(window.user),
receive: {
@@ -183,49 +177,49 @@ new Vue({
}
},
computed: {
filteredPayments: function() {
filteredPayments: function () {
var q = this.paymentsTable.filter
if (!q || q === '') return this.payments
return LNbits.utils.search(this.payments, q)
},
balance: function() {
balance: function () {
if (this.payments.length) {
return (
_.pluck(this.payments, 'amount').reduce(function(a, b) {
_.pluck(this.payments, 'amount').reduce(function (a, b) {
return a + b
}, 0) / 1000
)
}
return this.g.wallet.sat
},
fbalance: function() {
fbalance: function () {
return LNbits.utils.formatSat(this.balance)
},
canPay: function() {
canPay: function () {
if (!this.send.invoice) return false
return this.send.invoice.sat <= this.balance
},
pendingPaymentsExist: function() {
pendingPaymentsExist: function () {
return this.payments
? _.where(this.payments, {pending: 1}).length > 0
: false
}
},
methods: {
closeCamera: function() {
closeCamera: function () {
this.sendCamera.show = false
},
showCamera: function() {
showCamera: function () {
this.sendCamera.show = true
},
showChart: function() {
showChart: function () {
this.paymentsChart.show = true
this.$nextTick(function() {
this.$nextTick(function () {
generateChart(this.$refs.canvas, this.payments)
})
},
showReceiveDialog: function() {
showReceiveDialog: function () {
this.receive = {
show: true,
status: 'pending',
@@ -237,7 +231,7 @@ new Vue({
paymentChecker: null
}
},
showSendDialog: function() {
showSendDialog: function () {
this.send = {
show: true,
invoice: null,
@@ -247,20 +241,20 @@ new Vue({
paymentChecker: null
}
},
closeReceiveDialog: function() {
closeReceiveDialog: function () {
var checker = this.receive.paymentChecker
setTimeout(function() {
setTimeout(function () {
clearInterval(checker)
}, 10000)
},
closeSendDialog: function() {
closeSendDialog: function () {
this.sendCamera.show = false
var checker = this.send.paymentChecker
setTimeout(function() {
setTimeout(function () {
clearInterval(checker)
}, 1000)
},
createInvoice: function() {
createInvoice: function () {
var self = this
this.receive.status = 'loading'
LNbits.api
@@ -269,14 +263,14 @@ new Vue({
this.receive.data.amount,
this.receive.data.memo
)
.then(function(response) {
.then(function (response) {
self.receive.status = 'success'
self.receive.paymentReq = response.data.payment_request
self.receive.paymentChecker = setInterval(function() {
self.receive.paymentChecker = setInterval(function () {
LNbits.api
.getPayment(self.g.wallet, response.data.payment_hash)
.then(function(response) {
.then(function (response) {
if (response.data.paid) {
self.fetchPayments()
self.receive.show = false
@@ -285,17 +279,17 @@ new Vue({
})
}, 2000)
})
.catch(function(error) {
.catch(function (error) {
LNbits.utils.notifyApiError(error)
self.receive.status = 'pending'
})
},
decodeQR: function(res) {
decodeQR: function (res) {
this.send.data.bolt11 = res
this.decodeInvoice()
this.sendCamera.show = false
},
decodeInvoice: function() {
decodeInvoice: function () {
if (this.send.data.bolt11.startsWith('lightning:')) {
this.send.data.bolt11 = this.send.data.bolt11.slice(10)
}
@@ -320,7 +314,7 @@ new Vue({
fsat: LNbits.utils.formatSat(invoice.human_readable_part.amount / 1000)
}
_.each(invoice.data.tags, function(tag) {
_.each(invoice.data.tags, function (tag) {
if (_.isObject(tag) && _.has(tag, 'description')) {
if (tag.description === 'payment_hash') {
cleanInvoice.hash = tag.value
@@ -341,7 +335,7 @@ new Vue({
this.send.invoice = Object.freeze(cleanInvoice)
},
payInvoice: function() {
payInvoice: function () {
var self = this
let dismissPaymentMsg = this.$q.notify({
@@ -352,11 +346,11 @@ new Vue({
LNbits.api
.payInvoice(this.g.wallet, this.send.data.bolt11)
.then(function(response) {
self.send.paymentChecker = setInterval(function() {
.then(function (response) {
self.send.paymentChecker = setInterval(function () {
LNbits.api
.getPayment(self.g.wallet, response.data.payment_hash)
.then(function(res) {
.then(function (res) {
if (res.data.paid) {
self.send.show = false
clearInterval(self.send.paymentChecker)
@@ -366,58 +360,58 @@ new Vue({
})
}, 2000)
})
.catch(function(error) {
.catch(function (error) {
dismissPaymentMsg()
LNbits.utils.notifyApiError(error)
})
},
deleteWallet: function(walletId, user) {
deleteWallet: function (walletId, user) {
LNbits.utils
.confirmDialog('Are you sure you want to delete this wallet?')
.onOk(function() {
.onOk(function () {
LNbits.href.deleteWallet(walletId, user)
})
},
fetchPayments: function(checkPending) {
fetchPayments: function (checkPending) {
var self = this
return LNbits.api
.getPayments(this.g.wallet, checkPending)
.then(function(response) {
.then(function (response) {
self.payments = response.data
.map(function(obj) {
.map(function (obj) {
return LNbits.map.payment(obj)
})
.sort(function(a, b) {
.sort(function (a, b) {
return b.time - a.time
})
})
},
checkPendingPayments: function() {
checkPendingPayments: function () {
var dismissMsg = this.$q.notify({
timeout: 0,
message: 'Checking pending transactions...',
icon: null
})
this.fetchPayments(true).then(function() {
this.fetchPayments(true).then(function () {
dismissMsg()
})
},
exportCSV: function() {
exportCSV: function () {
LNbits.utils.exportCSV(this.paymentsTable.columns, this.payments)
}
},
watch: {
payments: function() {
payments: function () {
EventHub.$emit('update-wallet-balance', [this.g.wallet.id, this.balance])
}
},
created: function() {
created: function () {
this.fetchPayments()
setTimeout(this.checkPendingPayments(), 1200)
},
mounted: function() {
mounted: function () {
if (
this.$refs.disclaimer &&
!this.$q.localStorage.getItem('lnbits.disclaimerShown')
+74 -7
View File
@@ -103,19 +103,28 @@
<q-icon
v-if="props.row.isPaid"
size="14px"
:name="(props.row.sat < 0) ? 'call_made' : 'call_received'"
:color="(props.row.sat < 0) ? 'pink' : 'green'"
:name="props.row.isOut ? 'call_made' : 'call_received'"
:color="props.row.isOut ? 'pink' : 'green'"
@click="props.expand = !props.expand"
></q-icon>
<q-icon v-else name="settings_ethernet" color="grey">
<q-icon
v-else
name="settings_ethernet"
color="grey"
@click="props.expand = !props.expand"
>
<q-tooltip>Pending</q-tooltip>
</q-icon>
</q-td>
<q-td key="memo" :props="props">
<q-badge v-if="props.row.tag" color="yellow" text-color="black">
<a class="inherit" :href="['/', props.row.tag, '?usr=', user.id].join('')">
#{{ props.row.tag }}
</a>
</q-badge>
<a
class="inherit"
:href="['/', props.row.tag, '?usr=', user.id].join('')"
>
#{{ props.row.tag }}
</a>
</q-badge>
{{ props.row.memo }}
</q-td>
<q-td auto-width key="date" :props="props">
@@ -125,6 +134,64 @@
{{ props.row.fsat }}
</q-td>
</q-tr>
<q-dialog v-model="props.expand" :props="props">
<q-card
v-if="props.row.amount > 0 && props.row.pending"
class="q-pa-lg q-pt-xl lnbits__dialog-card"
>
<div class="text-center q-mb-lg">
<a :href="'lightning:' + receive.paymentReq">
<q-responsive :ratio="1" class="q-mx-xl">
<qrcode
:value="receive.paymentReq"
:options="{width: 340}"
class="rounded-borders"
></qrcode>
</q-responsive>
</a>
</div>
<div class="row q-mt-lg">
<q-btn
outline
color="grey"
@click="copyText(receive.paymentReq)"
>Copy invoice</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Close</q-btn
>
</div>
</q-card>
<q-card v-else class="q-pa-lg q-pt-xl lnbits__dialog-card">
<div class="text-center q-mb-lg">
<div v-if="props.row.isPaid && props.row.isIn">
<q-icon
size="18px"
:name="'call_received'"
:color="'green'"
></q-icon>
Payment Received
</div>
<div v-else-if="props.row.isPaid && props.row.isOut">
<q-icon
size="18px"
:name="'call_made'"
:color="'pink'"
></q-icon>
Payment Sent
</div>
<div v-else>
<q-icon name="settings_ethernet" color="grey"></q-icon>
Outgoing payment pending
</div>
<q-tooltip>Payment Hash</q-tooltip>
<div class="text-wrap mono q-pa-md">
{{ props.row.payment_hash }}
</div>
</div>
</q-card>
</q-dialog>
</template>
{% endraw %}
</q-table>