feat: partial payment redesign
This commit is contained in:
parent
799fb99661
commit
e98e3504ad
63
lnbits/extensions/watchonly/static/components/fees/fees.html
Normal file
63
lnbits/extensions/watchonly/static/components/fees/fees.html
Normal file
|
@ -0,0 +1,63 @@
|
|||
<div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-2 q-pr-lg">Fee Rate:</div>
|
||||
<div class="col-3 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.number="feeRate"
|
||||
:rules="[val => !!val || 'Field is required']"
|
||||
type="number"
|
||||
label="sats/vbyte"
|
||||
@input="feeRateChanged"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<q-slider
|
||||
v-model="feeRate"
|
||||
color="orange"
|
||||
markers
|
||||
snap
|
||||
label
|
||||
label-always
|
||||
:label-value="getFeeRateLabel(feeRate)"
|
||||
:min="1"
|
||||
:max="recommededFees.fastestFee"
|
||||
@input="feeRateChanged"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="feeRate < recommededFees.hourFee || feeRate > recommededFees.fastestFee"
|
||||
class="row items-center no-wrap q-mb-md"
|
||||
>
|
||||
<div class="col-2 q-pr-lg"></div>
|
||||
<div class="col-10 q-pr-lg">
|
||||
<q-badge v-if="feeRate < recommededFees.hourFee" color="pink" size="lg">
|
||||
Warning! The fee is too low. The transaction might take a long time to
|
||||
confirm.
|
||||
</q-badge>
|
||||
<q-badge v-if="feeRate > recommededFees.fastestFee" color="pink">
|
||||
Warning! The fee is too high. You might be overpaying for this
|
||||
transaction.
|
||||
</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-2 q-pr-lg">Fee:</div>
|
||||
<div class="col-3 q-pr-lg">{{totalfee}} sats</div>
|
||||
<div class="col-7">
|
||||
<q-btn
|
||||
outline
|
||||
dense
|
||||
size="md"
|
||||
icon="refresh"
|
||||
color="grey"
|
||||
class="float-right"
|
||||
@click="refreshRecommendedFees()"
|
||||
>Refresh Fee Rates</q-btn
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
62
lnbits/extensions/watchonly/static/components/fees/fees.js
Normal file
62
lnbits/extensions/watchonly/static/components/fees/fees.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
async function fees(path) {
|
||||
const template = await loadTemplateAsync(path)
|
||||
Vue.component('fees', {
|
||||
name: 'fees',
|
||||
template,
|
||||
|
||||
props: ['totalfee', 'sats_denominated'],
|
||||
watch: {
|
||||
immediate: true,
|
||||
'totalfee': function(newVal, oldVal) {
|
||||
console.log('### ', newVal, oldVal)
|
||||
}
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
feeRate: 1,
|
||||
recommededFees: {
|
||||
fastestFee: 1,
|
||||
halfHourFee: 1,
|
||||
hourFee: 1,
|
||||
economyFee: 1,
|
||||
minimumFee: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
satBtc(val, showUnit = true) {
|
||||
return satOrBtc(val, showUnit, this['sats_denominated'])
|
||||
},
|
||||
feeRateChanged: function (newFeeRate) {
|
||||
console.log('### value', newFeeRate)
|
||||
this.$emit('update:fee-rate', +newFeeRate)
|
||||
},
|
||||
refreshRecommendedFees: async function () {
|
||||
const {
|
||||
bitcoin: {fees: feesAPI}
|
||||
} = mempoolJS()
|
||||
|
||||
const fn = async () => feesAPI.getFeesRecommended()
|
||||
this.recommededFees = await retryWithDelay(fn)
|
||||
},
|
||||
getFeeRateLabel: function (feeRate) {
|
||||
const fees = this.recommededFees
|
||||
if (feeRate >= fees.fastestFee)
|
||||
return `High Priority (${feeRate} sat/vB)`
|
||||
if (feeRate >= fees.halfHourFee)
|
||||
return `Medium Priority (${feeRate} sat/vB)`
|
||||
if (feeRate >= fees.hourFee) return `Low Priority (${feeRate} sat/vB)`
|
||||
return `No Priority (${feeRate} sat/vB)`
|
||||
}
|
||||
},
|
||||
|
||||
created: async function () {
|
||||
console.log('### created fees ')
|
||||
await this.refreshRecommendedFees()
|
||||
this.feeRate = this.recommededFees.halfHourFee
|
||||
this.feeRateChanged(this.recommededFees.halfHourFee)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -81,7 +81,9 @@ async function utxoList(path) {
|
|||
|
||||
computed: {
|
||||
columns: function () {
|
||||
return this.utxosTable.columns.filter(c => c.selectable ? this.selectable : true)
|
||||
return this.utxosTable.columns.filter(c =>
|
||||
c.selectable ? this.selectable : true
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ const watchOnly = async () => {
|
|||
await addressList('static/components/address-list/address-list.html')
|
||||
await history('static/components/history/history.html')
|
||||
await utxoList('static/components/utxo-list/utxo-list.html')
|
||||
await fees('static/components/fees/fees.html')
|
||||
await payment('static/components/payment/payment.html')
|
||||
|
||||
Vue.filter('reverse', function (value) {
|
||||
|
@ -82,7 +83,9 @@ const watchOnly = async () => {
|
|||
|
||||
showAddress: false,
|
||||
addressNote: '',
|
||||
showPayment: false
|
||||
showPayment: false,
|
||||
showCustomFee: false,
|
||||
feeValue: 0
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -238,10 +241,10 @@ const watchOnly = async () => {
|
|||
masterpub_fingerprint: walletAcount.fingerprint
|
||||
}
|
||||
},
|
||||
computeFee: function () {
|
||||
computeFee: function (feeRate) {
|
||||
const tx = this.createTx()
|
||||
this.payment.txSize = Math.round(txSize(tx))
|
||||
return this.payment.feeRate * this.payment.txSize
|
||||
return feeRate * this.payment.txSize
|
||||
},
|
||||
deletePaymentAddress: function (v) {
|
||||
const index = this.payment.data.indexOf(v)
|
||||
|
@ -257,18 +260,9 @@ const watchOnly = async () => {
|
|||
this.payment.changeWallet = this.walletAccounts[0]
|
||||
this.selectChangeAddress(this.payment.changeWallet)
|
||||
|
||||
await this.refreshRecommendedFees()
|
||||
this.payment.feeRate = this.payment.recommededFees.halfHourFee
|
||||
},
|
||||
getFeeRateLabel: function (feeRate) {
|
||||
const fees = this.payment.recommededFees
|
||||
if (feeRate >= fees.fastestFee)
|
||||
return `High Priority (${feeRate} sat/vB)`
|
||||
if (feeRate >= fees.halfHourFee)
|
||||
return `Medium Priority (${feeRate} sat/vB)`
|
||||
if (feeRate >= fees.hourFee) return `Low Priority (${feeRate} sat/vB)`
|
||||
return `No Priority (${feeRate} sat/vB)`
|
||||
},
|
||||
|
||||
addPaymentAddress: function () {
|
||||
this.payment.data.push({address: '', amount: undefined})
|
||||
},
|
||||
|
@ -300,7 +294,7 @@ const watchOnly = async () => {
|
|||
createPsbt: async function () {
|
||||
const wallet = this.g.user.wallets[0]
|
||||
try {
|
||||
this.computeFee()
|
||||
this.computeFee(this.payment.feeRate)
|
||||
const tx = this.createTx()
|
||||
txSize(tx)
|
||||
for (const input of tx.inputs) {
|
||||
|
@ -824,7 +818,6 @@ const watchOnly = async () => {
|
|||
h => h.address !== addrData.address
|
||||
)
|
||||
|
||||
console.log('### addressHistory', addressHistory)
|
||||
// add new entries
|
||||
this.history.push(...addressHistory)
|
||||
this.history.sort((a, b) => (!a.height ? -1 : b.height - a.height))
|
||||
|
@ -899,14 +892,6 @@ const watchOnly = async () => {
|
|||
return this.addressHistoryFromTxs(addrData, addressTxs)
|
||||
},
|
||||
|
||||
refreshRecommendedFees: async function () {
|
||||
const {
|
||||
bitcoin: {fees: feesAPI}
|
||||
} = mempoolJS()
|
||||
|
||||
const fn = async () => feesAPI.getFeesRecommended()
|
||||
this.payment.recommededFees = await retryWithDelay(fn)
|
||||
},
|
||||
getAddressTxsUtxoDelayed: async function (address) {
|
||||
const {
|
||||
bitcoin: {addresses: addressesAPI}
|
||||
|
@ -974,6 +959,10 @@ const watchOnly = async () => {
|
|||
handleAddressesUpdated: async function (addresses) {
|
||||
this.addresses = addresses
|
||||
await this.scanAddressWithAmount()
|
||||
},
|
||||
handleFeeRateChanged: function (newFeeRate) {
|
||||
console.log('### newFeeRate', newFeeRate)
|
||||
this.feeValue = this.computeFee(newFeeRate)
|
||||
}
|
||||
},
|
||||
created: async function () {
|
||||
|
|
|
@ -48,14 +48,6 @@ const tableData = {
|
|||
changeAddress: {},
|
||||
changeAmount: 0,
|
||||
|
||||
feeRate: 1,
|
||||
recommededFees: {
|
||||
fastestFee: 1,
|
||||
halfHourFee: 1,
|
||||
hourFee: 1,
|
||||
economyFee: 1,
|
||||
minimumFee: 1
|
||||
},
|
||||
fee: 0,
|
||||
txSize: 0,
|
||||
tx: null,
|
||||
|
|
|
@ -500,7 +500,6 @@
|
|||
class="bg-dark text-white shadow-2"
|
||||
>
|
||||
<q-tab name="destination" label="Send To"></q-tab>
|
||||
<q-tab name="fees" label="Fees"></q-tab>
|
||||
<q-tab name="coinControl" label="Coin Control"></q-tab>
|
||||
</q-tabs>
|
||||
<q-tab-panels v-model="paymentTab">
|
||||
|
@ -596,6 +595,7 @@
|
|||
</q-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-12">
|
||||
<q-table
|
||||
|
@ -660,78 +660,29 @@
|
|||
-->
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
<div class="row items-center no-wrap q-mb-md q-pt-lg">
|
||||
<div class="col-12">
|
||||
<q-toggle
|
||||
label="Custom Fee"
|
||||
color="secodary"
|
||||
v-model="showCustomFee"
|
||||
></q-toggle>
|
||||
</div>
|
||||
</div>
|
||||
<q-card v-show="showCustomFee">
|
||||
<q-card-section>
|
||||
<div class="row items-center no-wrap q-mb-md q-pt-md">
|
||||
<div class="col-12">
|
||||
<fees
|
||||
:totalfee="feeValue"
|
||||
@update:fee-rate="handleFeeRateChanged"
|
||||
></fees>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="fees">
|
||||
<q-card
|
||||
><q-card-section>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-2 q-pr-lg">Fee Rate:</div>
|
||||
<div class="col-3 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.number="payment.feeRate"
|
||||
:rules="[val => !!val || 'Field is required']"
|
||||
type="number"
|
||||
label="sats/vbyte"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<q-slider
|
||||
v-model="payment.feeRate"
|
||||
color="orange"
|
||||
markers
|
||||
snap
|
||||
label
|
||||
label-always
|
||||
:label-value="getFeeRateLabel(payment.feeRate)"
|
||||
:min="1"
|
||||
:max="payment.recommededFees.fastestFee"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="payment.feeRate < payment.recommededFees.hourFee || payment.feeRate > payment.recommededFees.fastestFee"
|
||||
class="row items-center no-wrap q-mb-md"
|
||||
>
|
||||
<div class="col-2 q-pr-lg"></div>
|
||||
<div class="col-10 q-pr-lg">
|
||||
<q-badge
|
||||
v-if="payment.feeRate < payment.recommededFees.hourFee"
|
||||
color="pink"
|
||||
size="lg"
|
||||
>
|
||||
Warning! The fee is too low. The transaction might take
|
||||
a long time to confirm.
|
||||
</q-badge>
|
||||
<q-badge
|
||||
v-if="payment.feeRate > payment.recommededFees.fastestFee"
|
||||
color="pink"
|
||||
>
|
||||
Warning! The fee is too high. You might be overpaying
|
||||
for this transaction.
|
||||
</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-2 q-pr-lg">Fee:</div>
|
||||
<div class="col-3 q-pr-lg">{{computeFee()}} sats</div>
|
||||
<div class="col-7 q-pr-lg">
|
||||
<q-btn
|
||||
outline
|
||||
dense
|
||||
size="md"
|
||||
icon="refresh"
|
||||
color="grey"
|
||||
@click="refreshRecommendedFees()"
|
||||
>Refresh Fee Rates</q-btn
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section></q-card
|
||||
>
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="coinControl">
|
||||
<utxo-list
|
||||
:utxos="utxos.data"
|
||||
|
@ -998,6 +949,7 @@
|
|||
<script src="{{ url_for('watchonly_static', path='components/address-list/address-list.js') }}"></script>
|
||||
<script src="{{ url_for('watchonly_static', path='components/history/history.js') }}"></script>
|
||||
<script src="{{ url_for('watchonly_static', path='components/utxo-list/utxo-list.js') }}"></script>
|
||||
<script src="{{ url_for('watchonly_static', path='components/fees/fees.js') }}"></script>
|
||||
<script src="{{ url_for('watchonly_static', path='components/payment/payment.js') }}"></script>
|
||||
<script src="{{ url_for('watchonly_static', path='js/index.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in New Issue
Block a user