mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-21 22:11:48 +01:00
Wallet UI quick wins (#5851)
- Unify single/multiple inputs display - Destination: Move labels above amount - Coin Selection: Add sorting by amount and confirmations, add page size. Closes #5850 - Move PSBT and BIP21 buttons up to input related button group - Turn checkboxes in Advanced Settings into toggles - Improve spacings and button groups
This commit is contained in:
parent
7de4e8b001
commit
a8e16b0ba6
4 changed files with 180 additions and 204 deletions
|
@ -44,7 +44,7 @@ namespace BTCPayServer.Models.WalletViewModels
|
|||
|
||||
public List<FeeRateOption> RecommendedSatoshiPerByte { get; set; }
|
||||
|
||||
[Display(Name = "Fee rate (satoshi per byte)")]
|
||||
[Display(Name = "Fee rate (sat/vB)")]
|
||||
[Required]
|
||||
public decimal? FeeSatoshiPerByte { get; set; }
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@model WalletSendModel
|
||||
|
||||
<div class="form-group hide-when-js mt-4">
|
||||
<div class="form-group hide-when-js">
|
||||
<label asp-for="SelectedInputs" class="form-label"></label>
|
||||
<select multiple="multiple" asp-for="SelectedInputs" class="form-select">
|
||||
@foreach (var input in Model.InputsAvailable)
|
||||
|
@ -9,7 +9,12 @@
|
|||
}
|
||||
</select>
|
||||
</div>
|
||||
<div id="coin-selection-app" class="only-for-js mt-4" v-cloak>
|
||||
<style>
|
||||
#coin-selection-app .btn-link { --btcpay-btn-color: var(--btcpay-body-text-muted); }
|
||||
#coin-selection-app .btn-link:hover { --btcpay-btn-color: var(--btcpay-body-link-accent); }
|
||||
#coin-selection-app .btn-link.active { --btcpay-btn-active-color: var(--btcpay-body-link); }
|
||||
</style>
|
||||
<div id="coin-selection-app" class="only-for-js" v-cloak>
|
||||
<div class="d-sm-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-sm-0">Coin selection</h5>
|
||||
<span class="text-muted text-end">
|
||||
|
@ -18,11 +23,13 @@
|
|||
<span>/ {{items.length}} total (@Model.CurrentBalance @Model.CryptoCode)</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="input-group my-3">
|
||||
<input type="text" v-model="filter" class="form-control" placeholder="Filter by transaction id, amount, label, comment.."/>
|
||||
<button type="button" class="btn btn-secondary" title="Clear" v-on:click="filter=''" :disabled="!filter">
|
||||
<span class="fa fa-times"></span>
|
||||
</button>
|
||||
<input type="text" v-model="filter" class="form-control my-3" placeholder="Filter by transaction id, amount, label, comment.."/>
|
||||
<div class="d-flex gap-3 my-2 align-items-center">
|
||||
<span>Sort by</span>
|
||||
<div class="btn-group gap-3" role="group">
|
||||
<button type="button" class="btn btn-link p-0" :class="{active: sortOrder.startsWith('amount')}" v-on:click="sortBy('amount')">Amount</button>
|
||||
<button type="button" class="btn btn-link p-0" :class="{active: sortOrder.startsWith('confs')}" v-on:click="sortBy('confs')">Confirmations</button>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush mb-3" v-show="filteredItems.length">
|
||||
<li class="list-group-item py-2 cursor-pointer gap-2 align-items-center justify-content-between"
|
||||
|
@ -61,29 +68,38 @@
|
|||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="pagination" v-show="currentItems.length > pageSize">
|
||||
<li class="page-item" :class="{'disabled' : pageStart == 0}">
|
||||
<a class="page-link" tabindex="-1" href="#" v-on:click="page = page -1">«</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link">
|
||||
Showing {{pageStart+1}}-{{pageEnd}} of {{currentItems.length}}
|
||||
</span>
|
||||
</li>
|
||||
<li class="page-item" :class="{'disabled' : pageEnd>= currentItems.length}">
|
||||
<a class="page-link" href="#" v-on:click="page = page +1">»</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button type="button" :disabled="selectedInputs.length === 0" v-on:click="showSelectedOnly = !showSelectedOnly" class="btn btn-sm btn-secondary">
|
||||
<template v-if="showSelectedOnly">Show all</template>
|
||||
<template v-else>Show selected only</template>
|
||||
</button>
|
||||
<button type="button" :disabled="showSelectedOnly" v-on:click="showUnconfirmedOnly = !showUnconfirmedOnly" class="btn btn-sm btn-secondary" v-if="hasUnconfirmed">
|
||||
<template v-if="showUnconfirmedOnly">Show unconfirmed coins</template>
|
||||
<template v-else>Hide unconfirmed coins</template>
|
||||
</button>
|
||||
<div class="d-grid d-sm-flex flex-wrap gap-3 justify-content-between">
|
||||
<ul class="pagination">
|
||||
<li class="page-item" :class="{'disabled' : pageStart == 0}">
|
||||
<a class="page-link p-0" tabindex="-1" href="#" v-on:click.prevent="page = page -1">«</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link p-0">
|
||||
Showing {{pageStart+1}}-{{pageEnd}} of {{currentItems.length}}
|
||||
</span>
|
||||
</li>
|
||||
<li class="page-item" :class="{'disabled' : pageEnd>= currentItems.length}">
|
||||
<a class="page-link p-0" href="#" v-on:click.prevent="page = page +1">»</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="btn-group gap-3">
|
||||
<button type="button" :disabled="selectedInputs.length === 0" v-on:click="showSelectedOnly = !showSelectedOnly; page = 0" class="btn btn-link p-0">
|
||||
<template v-if="showSelectedOnly">Show all</template>
|
||||
<template v-else>Show selected only</template>
|
||||
</button>
|
||||
<button type="button" :disabled="showSelectedOnly" v-on:click="showUnconfirmedOnly = !showUnconfirmedOnly; page = 0" class="btn btn-link p-0" v-if="hasUnconfirmed">
|
||||
<template v-if="showUnconfirmedOnly">Show unconfirmed coins</template>
|
||||
<template v-else>Hide unconfirmed coins</template>
|
||||
</button>
|
||||
</div>
|
||||
<div class="d-flex gap-2 align-items-center">
|
||||
<span class="text-muted">Page Size:</span>
|
||||
<div class="btn-group gap-3" role="group">
|
||||
<button type="button" class="btn btn-link p-0" :class="{active: pageSize === 10}" v-on:click="pageSize = 10; page = 0">10</button>
|
||||
<button type="button" class="btn btn-link p-0" :class="{active: pageSize === 25}" v-on:click="pageSize = 25; page = 0">25</button>
|
||||
<button type="button" class="btn btn-link p-0" :class="{active: pageSize === 50}" v-on:click="pageSize = 50; page = 0">50</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -111,7 +127,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
page: 0,
|
||||
pageSize: 10,
|
||||
showSelectedOnly: false,
|
||||
showUnconfirmedOnly: false
|
||||
showUnconfirmedOnly: false,
|
||||
sortOrder: 'amount-desc'
|
||||
},
|
||||
watch: {
|
||||
filter: function() {
|
||||
|
@ -130,7 +147,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
},
|
||||
computed: {
|
||||
currentItems: function() {
|
||||
return this.showSelectedOnly ? this.selectedItems : this.items.filter(i=> (!this.showUnconfirmedOnly || i.confirmations ));
|
||||
const items = this.showSelectedOnly ? this.selectedItems : this.items.filter(i=> (!this.showUnconfirmedOnly || i.confirmations ));
|
||||
return this.sorted(items);
|
||||
},
|
||||
pageStart: function() {
|
||||
return this.page === 0 ? 0 : this.page * this.pageSize;
|
||||
|
@ -199,6 +217,20 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
});
|
||||
},
|
||||
methods: {
|
||||
sorted: function(items) {
|
||||
switch (this.sortOrder) {
|
||||
case 'amount-desc': return items.sort((a, b) => b.amount - a.amount)
|
||||
case 'amount-asc': return items.sort((a, b) => a.amount - b.amount)
|
||||
case 'confs-desc': return items.sort((a, b) => b.confirmations - a.confirmations)
|
||||
case 'confs-asc': return items.sort((a, b) => a.confirmations - b.confirmations)
|
||||
default: return items;
|
||||
}
|
||||
},
|
||||
sortBy: function(type) {
|
||||
this.sortOrder = this.sortOrder === `${type}-desc` ? `${type}-asc` : `${type}-desc`
|
||||
// reset page
|
||||
this.page = 0;
|
||||
},
|
||||
handle: function() {
|
||||
if (this.selectedInputs.length == 0) {
|
||||
this.showSelectedOnly = false;
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
border-top-right-radius: .2rem !important;
|
||||
border-bottom-right-radius: .2rem !important;
|
||||
}
|
||||
.buttons .btn {
|
||||
flex: 1 0 45%;
|
||||
}
|
||||
</style>
|
||||
<link href="~/vendor/tom-select/tom-select.bootstrap5.min.css" asp-append-version="true" rel="stylesheet">
|
||||
<script src="~/vendor/tom-select/tom-select.complete.min.js" asp-append-version="true"></script>
|
||||
|
@ -57,7 +60,7 @@
|
|||
<h1>@ViewData["Title"]</h1>
|
||||
</header>
|
||||
|
||||
<form method="post" asp-action="WalletSend" asp-route-walletId="@walletId" class="my-5">
|
||||
<form method="post" asp-action="WalletSend" asp-route-walletId="@walletId" class="my-5" id="SendForm">
|
||||
<input type="hidden" asp-for="InputSelection" />
|
||||
<input type="hidden" asp-for="FiatDivisibility" />
|
||||
<input type="hidden" asp-for="CryptoDivisibility" />
|
||||
|
@ -83,152 +86,101 @@
|
|||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
@if (Model.Outputs.Count == 1)
|
||||
{
|
||||
<div class="form-group">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<label asp-for="Outputs[0].DestinationAddress" class="form-label"></label>
|
||||
<button type="submit" name="command" value="add-output" class="d-inline-block ms-2 btn text-primary btn-link p-0 mb-2">
|
||||
<span class="fa fa-plus"></span> Add another destination
|
||||
</button>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input asp-for="Outputs[0].DestinationAddress" class="form-control font-monospace flex-grow-1" autofocus autocomplete="off" />
|
||||
<button type="button" id="scanqrcode" class="btn btn-secondary px-3 only-for-js" data-bs-toggle="modal" data-bs-target="#scanModal" title="Scan BIP21/Address with camera">
|
||||
<vc:icon symbol="scan-qr" />
|
||||
</button>
|
||||
</div>
|
||||
<span asp-validation-for="Outputs[0].DestinationAddress" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<label asp-for="Outputs[0].Amount" class="form-label"></label>
|
||||
<button type="submit" name="command" value="toggle-input-selection" class="d-inline-block ms-2 btn text-primary btn-link p-0 mb-2" id="toggleInputSelection"><span class="fa fa-@(Model.InputSelection ? "eye-slash" : "eye") "></span> @(Model.InputSelection ? "Hide" : "Show") coin selection</button>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input asp-for="Outputs[0].Amount" type="number" inputmode="decimal" step="any" min="0" asp-format="{0}" class="form-control output-amount hide-number-spin" />
|
||||
<div class="input-group-text fiat-value" style="display:none;">
|
||||
<span class="input-group-text p-0 border-0">=</span>
|
||||
<input type="number" inputmode="decimal" class="input-group-text fiat-value-edit-input py-0 border-0 hide-number-spin" min="0" step="any" style="max-width:100px" />
|
||||
<span class="input-group-text p-0 border-0">@Model.Fiat</span>
|
||||
</div>
|
||||
</div>
|
||||
<span asp-validation-for="Outputs[0].Amount" class="text-danger"></span>
|
||||
<div class="form-text crypto-info">
|
||||
Your available balance is
|
||||
<button type="button" class="crypto-balance-link btn btn-link p-0 align-baseline">@Model.CurrentBalance</button> <span>@Model.CryptoCode</span>.
|
||||
@if (Model.ImmatureBalance > 0)
|
||||
{
|
||||
<span>
|
||||
<br>
|
||||
<span class="info-note text-warning">
|
||||
<vc:icon symbol="warning"/>
|
||||
@Model.ImmatureBalance @Model.CryptoCode are still immature and require additional confirmations.
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Labels</label>
|
||||
<select asp-for="Outputs[0].Labels" class="d-none">
|
||||
@foreach (var t in Model.Outputs[0].Labels)
|
||||
{
|
||||
<option value="@t" selected></option>
|
||||
}
|
||||
</select>
|
||||
<vc:label-manager
|
||||
selected-labels="Model.Outputs[0].Labels"
|
||||
exclude-types="true"
|
||||
select-element="Outputs_0__Labels"
|
||||
wallet-object-id="new WalletObjectId(WalletId.Parse(walletId), WalletObjectData.Types.Address, Model.Outputs[0].DestinationAddress)"
|
||||
auto-update="false" />
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="list-group list-group-flush">
|
||||
@for (var index = 0; index < Model.Outputs.Count; index++)
|
||||
{
|
||||
<input type="hidden" asp-for="Outputs[index].PayoutId" />
|
||||
<div class="list-group-item d-block px-0 pt-0 pb-3 mb-3">
|
||||
<div class="form-group">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<label asp-for="Outputs[index].DestinationAddress" class="form-label"></label>
|
||||
<div class="list-group list-group-flush">
|
||||
@for (var index = 0; index < Model.Outputs.Count; index++)
|
||||
{
|
||||
<input type="hidden" asp-for="Outputs[index].PayoutId" />
|
||||
<div class="list-group-item d-block px-0 pt-0 pb-3 mb-3">
|
||||
<div class="form-group">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<label asp-for="Outputs[index].DestinationAddress" class="form-label"></label>
|
||||
@if (Model.Outputs.Count > 1)
|
||||
{
|
||||
<button type="submit" name="command" value="@($"remove-output:{index}")" class="d-inline-block ms-2 btn text-danger btn-link p-0 mb-2">
|
||||
<span class="fa fa-times"></span> Remove Destination
|
||||
</button>
|
||||
</div>
|
||||
<input asp-for="Outputs[index].DestinationAddress" class="form-control" autocomplete="off"/>
|
||||
<span asp-validation-for="Outputs[index].DestinationAddress" class="text-danger"></span>
|
||||
}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Outputs[index].Amount" class="form-label"></label>
|
||||
<div class="input-group">
|
||||
<input asp-for="Outputs[index].Amount" type="number" min="0" step="any" asp-format="{0}" class="form-control output-amount hide-number-spin" />
|
||||
<div class="input-group-text fiat-value" style="display:none;">
|
||||
<span class="input-group-text p-0 border-0">=</span>
|
||||
<input type="number" inputmode="decimal" class="input-group-text fiat-value-edit-input py-0 border-0 hide-number-spin" min="0" step="any" style="max-width:100px" />
|
||||
<span class="input-group-text p-0 border-0">@Model.Fiat</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-text crypto-info">
|
||||
Your available balance is
|
||||
<button type="button" class="crypto-balance-link btn btn-link p-0 align-baseline">@Model.CurrentBalance</button> <span>@Model.CryptoCode</span>.
|
||||
@if (Model.ImmatureBalance > 0)
|
||||
{
|
||||
<span><br>Note: @Model.ImmatureBalance @Model.CryptoCode are still immature and require additional confirmations.</span>
|
||||
}
|
||||
</div>
|
||||
<span asp-validation-for="Outputs[index].Amount" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" asp-for="Outputs[index].SubtractFeesFromOutput" class="form-check-input subtract-fees" />
|
||||
<label asp-for="Outputs[index].SubtractFeesFromOutput" class="form-check-label"></label>
|
||||
<span asp-validation-for="Outputs[index].SubtractFeesFromOutput" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Labels</label>
|
||||
<select asp-for="Outputs[index].Labels" class="d-none">
|
||||
@foreach (var t in Model.Outputs[index].Labels)
|
||||
{
|
||||
<option value="@t" selected></option>
|
||||
}
|
||||
</select>
|
||||
<vc:label-manager
|
||||
selected-labels="Model.Outputs[index].Labels"
|
||||
exclude-types="true"
|
||||
select-element="Outputs_@(index)__Labels"
|
||||
wallet-object-id="new WalletObjectId(WalletId.Parse(walletId), WalletObjectData.Types.Address, Model.Outputs[index].DestinationAddress)"
|
||||
auto-update="false" />
|
||||
<div class="input-group">
|
||||
<input asp-for="Outputs[index].DestinationAddress" class="form-control font-monospace flex-grow-1" autocomplete="off" autofocus="@(index == Model.Outputs.Count - 1 ? "autofocus" : null)"/>
|
||||
<button type="button" id="scanqrcode" class="btn btn-secondary px-3 only-for-js" data-bs-toggle="modal" data-bs-target="#scanModal" title="Scan with camera" data-index="@index">
|
||||
<vc:icon symbol="scan-qr" />
|
||||
</button>
|
||||
</div>
|
||||
<span asp-validation-for="Outputs[index].DestinationAddress" class="text-danger"></span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="d-grid gap-3 d-md-block mt-n2">
|
||||
<button type="submit" name="command" value="add-output" class="btn btn-secondary me-md-1"><span class="fa fa-plus"></span> Add another destination</button>
|
||||
<button type="submit" name="command" value="toggle-input-selection" class="btn btn-secondary" id="toggleInputSelection"><span class="fa fa-@(Model.InputSelection ? "eye-slash" : "eye") "></span> @(Model.InputSelection ? "Hide" : "Show") coin selection</button>
|
||||
</div>
|
||||
}
|
||||
<div class="form-group">
|
||||
<label class="form-label">Labels</label>
|
||||
<select asp-for="Outputs[index].Labels" class="d-none">
|
||||
@foreach (var t in Model.Outputs[index].Labels)
|
||||
{
|
||||
<option value="@t" selected></option>
|
||||
}
|
||||
</select>
|
||||
<vc:label-manager
|
||||
selected-labels="Model.Outputs[index].Labels"
|
||||
exclude-types="true"
|
||||
select-element="Outputs_@(index)__Labels"
|
||||
wallet-object-id="new WalletObjectId(WalletId.Parse(walletId), WalletObjectData.Types.Address, Model.Outputs[index].DestinationAddress)"
|
||||
auto-update="false" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Outputs[index].Amount" class="form-label"></label>
|
||||
<div class="input-group">
|
||||
<input asp-for="Outputs[index].Amount" type="number" min="0" step="any" asp-format="{0}" class="form-control output-amount hide-number-spin" />
|
||||
<div class="input-group-text fiat-value" style="display:none;">
|
||||
<span class="input-group-text p-0 border-0">=</span>
|
||||
<input type="number" inputmode="decimal" class="input-group-text fiat-value-edit-input py-0 border-0 hide-number-spin" min="0" step="any" style="max-width:100px" />
|
||||
<span class="input-group-text p-0 border-0">@Model.Fiat</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-text crypto-info">
|
||||
Your available balance is
|
||||
<button type="button" class="crypto-balance-link btn btn-link p-0 align-baseline">@Model.CurrentBalance</button> <span>@Model.CryptoCode</span>.
|
||||
@if (Model.ImmatureBalance > 0)
|
||||
{
|
||||
<span><br>Note: @Model.ImmatureBalance @Model.CryptoCode are still immature and require additional confirmations.</span>
|
||||
}
|
||||
</div>
|
||||
<span asp-validation-for="Outputs[index].Amount" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-check mb-0">
|
||||
<input type="checkbox" asp-for="Outputs[index].SubtractFeesFromOutput" class="form-check-input subtract-fees" />
|
||||
<label asp-for="Outputs[index].SubtractFeesFromOutput" class="form-check-label"></label>
|
||||
<span asp-validation-for="Outputs[index].SubtractFeesFromOutput" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="d-grid d-sm-flex flex-wrap gap-3 mb-3 buttons">
|
||||
<button type="submit" name="command" value="add-output" class="btn btn-secondary">Add destination</button>
|
||||
<button type="submit" name="command" value="toggle-input-selection" class="btn btn-secondary" id="toggleInputSelection">@(Model.InputSelection ? "Hide" : "Show") coin selection</button>
|
||||
<a asp-controller="UIWallets" asp-action="WalletPSBT" asp-route-walletId="@walletId" asp-route-returnUrl="@Model.ReturnUrl" class="btn btn-secondary" id="PSBT">Use PSBT</a>
|
||||
<button type="button" id="bip21parse" class="btn btn-secondary">Paste BIP21</button>
|
||||
</div>
|
||||
|
||||
@if (Model.InputSelection)
|
||||
{
|
||||
<partial name="CoinSelection" />
|
||||
<div class="my-5">
|
||||
<partial name="CoinSelection" />
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="form-group my-4">
|
||||
<label asp-for="FeeSatoshiPerByte" class="form-label"></label>
|
||||
<input asp-for="FeeSatoshiPerByte" type="number" inputmode="numeric" min="0" step="any" class="form-control" style="max-width:14ch;" />
|
||||
<span asp-validation-for="FeeSatoshiPerByte" class="text-danger"></span>
|
||||
<span id="FeeRate-Error" class="text-danger"></span>
|
||||
<div class="d-flex flex-wrap gap-3 my-4">
|
||||
<div>
|
||||
<label asp-for="FeeSatoshiPerByte" class="form-label">Fee rate <span class="text-secondary">(sat/vB)</span></label>
|
||||
<input asp-for="FeeSatoshiPerByte" type="number" inputmode="numeric" min="0" step="any" class="form-control" style="max-width:14ch;" />
|
||||
<span asp-validation-for="FeeSatoshiPerByte" class="text-danger"></span>
|
||||
<span id="FeeRate-Error" class="text-danger"></span>
|
||||
</div>
|
||||
@if (Model.RecommendedSatoshiPerByte.Any())
|
||||
{
|
||||
<div class="text-start mt-4 d-flex align-items-sm-center flex-column flex-sm-row">
|
||||
<span class="text-secondary me-3">
|
||||
Confirm in the next
|
||||
</span>
|
||||
<div class="btn-group btn-group-toggle feerate-options mt-2 mt-sm-0" role="group" data-bs-toggle="buttons">
|
||||
<div>
|
||||
<div class="form-label text-secondary">
|
||||
Confirm in the next …
|
||||
</div>
|
||||
<div class="btn-group btn-group-toggle feerate-options" role="group" data-bs-toggle="buttons">
|
||||
@for (var index = 0; index < Model.RecommendedSatoshiPerByte.Count; index++)
|
||||
{
|
||||
var feeRateOption = Model.RecommendedSatoshiPerByte[index];
|
||||
|
@ -242,16 +194,6 @@
|
|||
</div>
|
||||
}
|
||||
</div>
|
||||
@if (Model.Outputs.Count == 1)
|
||||
{
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" asp-for="Outputs[0].SubtractFeesFromOutput" class="form-check-input subtract-fees" />
|
||||
<label asp-for="Outputs[0].SubtractFeesFromOutput" class="form-check-label"></label>
|
||||
<span asp-validation-for="Outputs[0].SubtractFeesFromOutput" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="my-4">
|
||||
<button class="d-inline-flex align-items-center btn btn-link text-primary fw-semibold p-0" type="button" id="AdvancedSettingsButton" data-bs-toggle="collapse" data-bs-target="#AdvancedSettings" aria-expanded="false" aria-controls="AdvancedSettings">
|
||||
|
@ -259,40 +201,33 @@
|
|||
<span class="ms-1">Advanced settings</span>
|
||||
</button>
|
||||
<div id="AdvancedSettings" class="collapse">
|
||||
<div class="pt-3 pb-1">
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input asp-for="NoChange" class="form-check-input" />
|
||||
<label asp-for="NoChange" class="form-check-label"></label>
|
||||
<a href="https://docs.btcpayserver.org/Wallet/#dont-create-utxo-change" target="_blank" rel="noreferrer noopener">
|
||||
<vc:icon symbol="info" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input asp-for="AlwaysIncludeNonWitnessUTXO" class="form-check-input"/>
|
||||
<label asp-for="AlwaysIncludeNonWitnessUTXO" class="form-check-label"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-3">
|
||||
<div class="d-flex mb-3">
|
||||
<input asp-for="NoChange" class="btcpay-toggle me-3" />
|
||||
<label asp-for="NoChange" class="form-check-label me-1"></label>
|
||||
<a href="https://docs.btcpayserver.org/Wallet/#dont-create-utxo-change" target="_blank" rel="noreferrer noopener">
|
||||
<vc:icon symbol="info" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="d-flex mb-3">
|
||||
<input asp-for="AlwaysIncludeNonWitnessUTXO" class="btcpay-toggle me-3"/>
|
||||
<label asp-for="AlwaysIncludeNonWitnessUTXO" class="form-check-label"></label>
|
||||
</div>
|
||||
|
||||
@if (!string.IsNullOrEmpty(Model.PayJoinBIP21))
|
||||
{
|
||||
<div class="form-group">
|
||||
<div class="d-flex mb-3">
|
||||
<input asp-for="PayJoinBIP21" class="btcpay-toggle me-3" />
|
||||
<label asp-for="PayJoinBIP21" class="form-label"></label>
|
||||
<input asp-for="PayJoinBIP21" class="form-control" />
|
||||
<span asp-validation-for="PayJoinBIP21" class="text-danger"></span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group d-grid d-sm-flex flex-wrap gap-3 mt-2">
|
||||
<div class="d-grid d-sm-flex flex-wrap gap-3 buttons">
|
||||
<button type="submit" id="SignTransaction" name="command" value="sign" class="btn btn-primary">Sign transaction</button>
|
||||
<button type="submit" id="ScheduleTransaction" name="command" value="schedule" class="btn btn-secondary">Schedule transaction</button>
|
||||
<a class="btn btn-secondary" asp-controller="UIWallets" asp-action="WalletPSBT" asp-route-walletId="@walletId" asp-route-returnUrl="@Model.ReturnUrl" id="PSBT">PSBT</a>
|
||||
<button type="button" id="bip21parse" class="btn btn-secondary px-3" title="Paste BIP21/Address"><i class="fa fa-paste"></i></button>
|
||||
</div>
|
||||
|
||||
<vc:ui-extension-point location="onchain-wallet-send" model="@Model"/>
|
||||
<vc:ui-extension-point location="onchain-wallet-send" model="@Model"/>
|
||||
</form>
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
$(function () {
|
||||
initCameraScanningApp("Scan address/ payment link", data => {
|
||||
$("#BIP21").val(data);
|
||||
$("form").submit();
|
||||
window.addEventListener("load", () => {
|
||||
let $input = null;
|
||||
initCameraScanningApp("Scan address or payment link", data => {
|
||||
if (data.includes('?') || $input == null) {
|
||||
document.getElementById("BIP21").value = data;
|
||||
document.getElementById("SendForm").submit();
|
||||
} else {
|
||||
$input.value = data;
|
||||
}
|
||||
}, "scanModal");
|
||||
document.getElementById('scanModal').addEventListener('show.bs.modal', e => {
|
||||
const { index } = e.relatedTarget.dataset;
|
||||
$input = index ? document.querySelector(`[name="Outputs[${index}].DestinationAddress"]`) : null;
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue