Improve payouts UI (#3792)

* Improve payouts UI

* Display units

* Update badges

* Update badge background
This commit is contained in:
d11n 2022-06-02 11:03:06 +02:00 committed by GitHub
parent 5616b7550f
commit ba0e46b465
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 40 deletions

View File

@ -12,6 +12,7 @@ using BTCPayServer.Payments;
using BTCPayServer.Payments.Lightning;
using BTCPayServer.Security;
using BTCPayServer.Services;
using BTCPayServer.Services.Rates;
using BTCPayServer.Services.Stores;
using LNURL;
using Microsoft.AspNetCore.Authorization;
@ -35,6 +36,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
private readonly IOptions<LightningNetworkOptions> _options;
private readonly IAuthorizationService _authorizationService;
private readonly StoreRepository _storeRepository;
private readonly CurrencyNameTable _currencyNameTable;
public UILightningLikePayoutController(ApplicationDbContextFactory applicationDbContextFactory,
UserManager<ApplicationUser> userManager,
@ -42,6 +44,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
IEnumerable<IPayoutHandler> payoutHandlers,
BTCPayNetworkProvider btcPayNetworkProvider,
StoreRepository storeRepository,
CurrencyNameTable currencyNameTable,
LightningClientFactoryService lightningClientFactoryService,
IOptions<LightningNetworkOptions> options, IAuthorizationService authorizationService)
{
@ -53,6 +56,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
_lightningClientFactoryService = lightningClientFactoryService;
_options = options;
_storeRepository = storeRepository;
_currencyNameTable = currencyNameTable;
_authorizationService = authorizationService;
}
@ -103,7 +107,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
{
var blob = payoutData.GetBlob(_btcPayNetworkJsonSerializerSettings);
return new ConfirmVM()
return new ConfirmVM
{
Amount = blob.CryptoAmount.Value,
Destination = blob.Destination,
@ -133,11 +137,11 @@ namespace BTCPayServer.Data.Payouts.LightningLike
var boltAmount = bolt11PaymentRequest.MinimumAmount.ToDecimal(LightMoneyUnit.BTC);
if (boltAmount != payoutBlob.CryptoAmount)
{
results.Add(new ResultVM()
results.Add(new ResultVM
{
PayoutId = payoutData.Id,
Result = PayResult.Error,
Message = $"The BOLT11 invoice amount did not match the payout's amount ({boltAmount} instead of {payoutBlob.CryptoAmount})",
Message = $"The BOLT11 invoice amount ({_currencyNameTable.DisplayFormatCurrency(boltAmount, pmi.CryptoCode)}) did not match the payout's amount ({_currencyNameTable.DisplayFormatCurrency(payoutBlob.CryptoAmount.GetValueOrDefault(), pmi.CryptoCode)})",
Destination = payoutBlob.Destination
});
return;
@ -145,21 +149,26 @@ namespace BTCPayServer.Data.Payouts.LightningLike
var result = await lightningClient.Pay(bolt11PaymentRequest.ToString());
if (result.Result == PayResult.Ok)
{
results.Add(new ResultVM()
var message = result.Details?.TotalAmount != null
? $"Paid out {result.Details.TotalAmount.ToDecimal(LightMoneyUnit.BTC)}"
: null;
results.Add(new ResultVM
{
PayoutId = payoutData.Id,
Result = result.Result,
Destination = payoutBlob.Destination
Destination = payoutBlob.Destination,
Message = message
});
payoutData.State = PayoutState.Completed;
}
else
{
results.Add(new ResultVM()
results.Add(new ResultVM
{
PayoutId = payoutData.Id,
Result = result.Result,
Destination = payoutBlob.Destination
Destination = payoutBlob.Destination,
Message = result.ErrorDetail
});
}
}
@ -184,8 +193,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
PayoutId = payoutData.Id,
Result = PayResult.Error,
Destination = blob.Destination,
Message =
$"You are currently using the internal lightning node for this payout's store but you are not a server admin."
Message = "You are currently using the internal Lightning node for this payout's store but you are not a server admin."
});
}
@ -204,7 +212,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
switch (claim.destination)
{
case LNURLPayClaimDestinaton lnurlPayClaimDestinaton:
var endpoint = LNURL.LNURL.Parse(lnurlPayClaimDestinaton.LNURL, out var tag);
var endpoint = LNURL.LNURL.Parse(lnurlPayClaimDestinaton.LNURL, out _);
var lightningPayoutHandler = (LightningLikePayoutHandler)payoutHandler;
var httpClient = lightningPayoutHandler.CreateClient(endpoint);
var lnurlInfo =
@ -213,7 +221,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
var lm = new LightMoney(blob.CryptoAmount.Value, LightMoneyUnit.BTC);
if (lm > lnurlInfo.MaxSendable || lm < lnurlInfo.MinSendable)
{
results.Add(new ResultVM()
results.Add(new ResultVM
{
PayoutId = payoutData.Id,
Result = PayResult.Error,
@ -260,13 +268,14 @@ namespace BTCPayServer.Data.Payouts.LightningLike
break;
}
}
catch (Exception)
catch (Exception exception)
{
results.Add(new ResultVM
{
PayoutId = payoutData.Id,
Result = PayResult.Error,
Destination = blob.Destination
Destination = blob.Destination,
Message = exception.Message
});
}
}

View File

@ -5,20 +5,19 @@
var cryptoCode = Context.GetRouteValue("cryptoCode");
}
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<h2 class="mt-1 mb-2">@ViewData["Title"]</h2>
<div class="row">
<div class="col-md-12">
<ul class="list-group">
<ul class="list-group list-group-flush">
@foreach (var item in Model)
{
<li class="list-group-item d-flex justify-content-between align-items-center">
<div class="text-break" style="max-width:60em;">@item.Destination</div>
<span class="text-capitalize badge bg-secondary">@item.Amount @cryptoCode</span>
<li class="list-group-item py-4 px-0">
<div class="text-break">@item.Destination</div>
<form method="post" class="mt-4 mb-1" id="pay-invoices-form">
<button type="submit" class="btn btn-primary" id="Pay">Pay @item.Amount @cryptoCode</button>
<a asp-controller="UIStorePullPayments" asp-action="Payouts" asp-route-storeId="@Context.GetStoreData().Id" class="btn btn-secondary mx-2 px-4">Cancel</a>
</form>
</li>
<form method="post" class="list-group-item justify-content-center" id="pay-invoices-form">
<button type="submit" class="btn btn-primary px-5" id="Pay">Pay</button>
<a asp-controller="UIStorePullPayments" asp-action="Payouts" asp-route-storeId="@Context.GetStoreData().Id" class="btn btn-secondary mx-2 px-4">Cancel</a>
</form>
}
</ul>
</div>

View File

@ -8,15 +8,14 @@
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
@foreach (var item in Model)
{
<div class="alert alert-@(item.Result == PayResult.Ok ? "success" : "danger") d-flex justify-content-between align-items-center mb-3" role="alert">
@if (item.Result == PayResult.Ok)
{
<div class="text-break me-3" title="@item.Destination">@item.Destination</div>
}
else
{
<div class="text-break me-3" title="@item.Destination">@item.Destination: @item.Message (@item.Result)</div>
}
<span class="badge fs-5">@(item.Result == PayResult.Ok ? "Sent" : "Failed")</span>
<div class="alert alert-@(item.Result == PayResult.Ok ? "success" : "danger") mb-3" role="alert">
<h5 class="alert-heading">
@(item.Result == PayResult.Ok ? "Sent" : "Failed")
@if (!string.IsNullOrEmpty(item.Message))
{
<span>- @item.Message</span>
}
</h5>
<div class="text-break me-3" title="@item.Destination">@item.Destination</div>
</div>
}

View File

@ -39,6 +39,15 @@
}
}
@section PageHeadContent {
<style>
#Payouts .badge.rounded-pill {
font-size: var(--btcpay-font-size-s);
color: inherit;
}
</style>
}
@section PageFootContent {
<script>
delegate('click', '.selectAll', e => {
@ -52,10 +61,6 @@
<partial name="_StatusMessage"/>
@{
}
@if (_payoutProcessorFactories.Any(factory => factory.GetSupportedPaymentMethods().Contains(paymentMethodId)) && !(await _payoutProcessorService.GetProcessors(new PayoutProcessorService.PayoutProcessorQuery()
{
Stores = new[] {storeId},
@ -70,7 +75,7 @@
}
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<form method="post">
<form method="post" id="Payouts">
<input type="hidden" asp-for="PaymentMethodId"/>
<input type="hidden" asp-for="PayoutState"/>
<div class="d-flex justify-content-between mb-4">
@ -82,13 +87,13 @@
asp-route-payoutState="@Model.PayoutState"
asp-route-paymentMethodId="@state.ToString()"
asp-route-pullPaymentId="@Model.PullPaymentId"
class="btcpay-pill @(state.ToString() == Model.PaymentMethodId ? "active" : "")"
class="btcpay-pill position-relative @(state.ToString() == Model.PaymentMethodId ? "active" : "")"
id="@state.ToString()-view"
role="tab">
@state.ToPrettyString()
@if (Model.PaymentMethodCount.TryGetValue(state.ToString(), out var count) && count > 0)
{
<span>(@count)</span>
<span class="badge rounded-pill fw-semibold pe-0">@count</span>
}
</a>
</li>
@ -119,7 +124,11 @@
asp-route-pullPaymentId="@Model.PullPaymentId"
asp-route-paymentMethodId="@Model.PaymentMethodId"
class="nav-link @(state.Key == Model.PayoutState ? "active" : "")" role="tab">
@state.Key.GetStateString() (@state.Value)
@state.Key.GetStateString()
@if (state.Value > 0)
{
<span class="badge rounded-pill border fw-semibold ms-1 bg-tile">@state.Value</span>
}
</a>
}
</div>

View File

@ -41,6 +41,7 @@
--btcpay-secondary: transparent;
--btcpay-secondary-text-active: var(--btcpay-primary);
--btcpay-secondary-border: var(--btcpay-neutral-700);
--btcpay-secondary-rgb: 22, 27, 34;
--btcpay-light: var(--btcpay-neutral-800);
--btcpay-light-accent: var(--btcpay-black);
--btcpay-light-text: var(--btcpay-neutral-200);