Files
BTCPayServerPlugins/Plugins/BTCPayServer.Plugins.Prism/Components/PrismBalances.razor
2023-08-15 12:25:36 +02:00

122 lines
4.8 KiB
Plaintext

<div class="row mt-4">
@if (DestinationBalance is not null)
{
<div class="col-sm-12 col-md-12 col-lg-6 col-xxl-constrain border border-light">
<h4 class="text-center p-2">Destination Pending Balances</h4>
<p class="text-muted text-center p-2">These are the current balances of destinations. Once the threshold is reached for a destination, a payout is generated of that amount (minus the reserve fee amount to cover potential costs).</p>
<table class="table table-sm">
<tr>
<th>Destination</th>
<th>Sats</th>
<th>Actions</th>
</tr>
@foreach (var (dest, balance) in DestinationBalance)
{
<tr>
<td class="text-truncate" style="max-width: 200px">@dest</td>
<td>@(balance / 1000m)</td>
<td>
@if (UpdatingDestination == dest)
{
<input type="number" @bind="UpdatingValue" min="0"/>
<button type="button" class="btn btn-sm btn-link" @onclick="() => UpdatingDestination = null">Cancel</button>
<button type="button" class="btn btn-sm btn-link" @onclick="Update" disabled="@IsActionOngoing">Update</button>
}
else
{
<button type="button" class="btn btn-sm btn-link" @onclick="() => StartUpdate(dest, balance)" disabled="@IsActionOngoing">Update</button>
}
</td>
</tr>
}
</table>
</div>
}
@if (PendingPayouts is not null)
{
<div class="col-sm-12 col-md-12 col-lg-6 col-xxl-constrain border border-light">
<h4 class="text-center p-2">Pending Payouts</h4>
<p class="text-muted text-center p-2">These payouts were generated by Prism after a threshold for a destination was reached. If these payouts are cancelled, the original destination will be credited back the payout amount. If a payout completes, we attempt to get the actual fee spent to adjust the destination balance accordingly.</p>
<table class="table table-sm">
<tr>
<th>Payout Id</th>
<th>Destination</th>
<th>Reserve fee</th>
<th>Amount</th>
<th>Actions</th>
</tr>
@foreach (var (payoutId, pendingPayout) in PendingPayouts)
{
<tr>
<td style="word-break:break-all;">@payoutId</td>
<td style="word-break:break-all;">@pendingPayout.DestinationId</td>
<td style="word-break:break-all;">@pendingPayout.FeeCharged</td>
<td style="word-break:break-all;">@pendingPayout.PayoutAmount</td>
<td>
<button type="button" class="btn btn-sm btn-link" @onclick="() => CancelPayout(payoutId)" disabled="@IsActionOngoing">Cancel</button>
</td>
</tr>
}
</table>
</div>
}
</div>
@code {
private string? UpdatingDestination { get; set; }
private long? UpdatingValue { get; set; }
[Parameter]
public Dictionary<string, long> DestinationBalance { get; set; }
[Parameter]
public Dictionary<string, PendingPayout> PendingPayouts { get; set; }
[Parameter]
public EventCallback<(string destination, long newBalance)> OnUpdate { get; set; }
private bool IsActionOngoing { get; set; }
[Parameter]
public EventCallback<(string payoutId, TaskCompletionSource tcs)> OnCancelPayout { get; set; }
private EventCallback StartUpdate(string dest, long balance)
{
UpdatingDestination = dest;
UpdatingValue = Convert.ToInt32(balance / 1000m);
return EventCallback.Empty;
}
private async Task Update()
{
if (UpdatingDestination is null || UpdatingValue is null)
{
return;
}
await OnUpdate.InvokeAsync((UpdatingDestination, Convert.ToInt64(UpdatingValue.Value * 1000m)));
UpdatingDestination = null;
}
private async Task CancelPayout(string payoutId)
{
UpdatingDestination = null;
IsActionOngoing = true;
try
{
var tcs = new TaskCompletionSource();
await OnCancelPayout.InvokeAsync((payoutId, tcs));
await tcs.Task;
}
finally
{
IsActionOngoing = false;
}
}
}