Compare commits

..

14 Commits

Author SHA1 Message Date
4f9e4116a2 Point of Sale support free entry 2018-04-26 22:09:18 +09:00
82d8fda05f update clightning in tests 2018-04-26 15:30:52 +09:00
d4935263da Update various packages 2018-04-26 11:45:09 +09:00
e158d909fb bump 2018-04-26 11:16:56 +09:00
de8147d5dd Can opt out required refund email from customer 2018-04-26 11:13:44 +09:00
16f1791a9a Invoice filter must work with duplicated filter 2018-04-26 11:03:02 +09:00
8745c3f8c6 Merge pull request #139 from lepipele/dev-timerfix
Recoding timer removing dependecy on browser's setInterval
2018-04-26 09:18:04 +09:00
ec5b45cff6 Recoding timer removing dependecy on browser's setInterval
Ref: https://github.com/btcpayserver/btcpayserver/issues/130
2018-04-25 13:30:00 -05:00
1348197295 Merge pull request #134 from lepipele/master
Ellipsis when there is lots of info, preserving responsive tables
2018-04-24 12:00:54 +09:00
f2516854d8 Fixing width to align first columns
Ref: https://github.com/btcpayserver/btcpayserver/pull/134#issuecomment-383785811
2018-04-23 21:58:22 -05:00
062ca6e743 Merge remote-tracking branch 'source/master' 2018-04-23 21:53:06 -05:00
44b6997bb5 Merge pull request #136 from Saevar2000/patch-1
Update is.js
2018-04-24 11:39:11 +09:00
78b544f9ca Update is.js 2018-04-23 23:08:35 +00:00
81926b4450 Ellipsis when there is lots of info, preserving responsive tables
Ref: https://github.com/btcpayserver/btcpayserver/issues/133
2018-04-23 16:00:03 -05:00
23 changed files with 194 additions and 84 deletions

View File

@ -598,8 +598,18 @@ namespace BTCPayServer.Tests
var search = new SearchString(filter);
Assert.Equal("storeid:abc status:abed blabhbalh", search.ToString());
Assert.Equal("blabhbalh", search.TextSearch);
Assert.Equal("abc", search.Filters["storeid"]);
Assert.Equal("abed", search.Filters["status"]);
Assert.Single(search.Filters["storeid"]);
Assert.Single(search.Filters["status"]);
Assert.Equal("abc", search.Filters["storeid"].First());
Assert.Equal("abed", search.Filters["status"].First());
filter = "status:abed status:abed2";
search = new SearchString(filter);
Assert.Equal("status:abed status:abed2", search.ToString());
Assert.Throws<KeyNotFoundException>(() => search.Filters["test"]);
Assert.Equal(2, search.Filters["status"].Count);
Assert.Equal("abed", search.Filters["status"].First());
Assert.Equal("abed2", search.Filters["status"].Skip(1).First());
}
[Fact]
@ -987,7 +997,7 @@ namespace BTCPayServer.Tests
Assert.Equal("orange", vmview.Items[1].Title);
Assert.Equal(10.0m, vmview.Items[1].Price.Value);
Assert.Equal("$5.00", vmview.Items[0].Price.Formatted);
Assert.IsType<RedirectResult>(apps.ViewPointOfSale(appId, "orange").Result);
Assert.IsType<RedirectResult>(apps.ViewPointOfSale(appId, 0, "orange").Result);
var invoice = user.BitPay.GetInvoices().First();
Assert.Equal(10.00, invoice.Price);
Assert.Equal("CAD", invoice.Currency);
@ -1054,13 +1064,13 @@ namespace BTCPayServer.Tests
{
var textSearchResult = tester.PayTester.InvoiceRepository.GetInvoices(new InvoiceQuery()
{
StoreId = user.StoreId,
StoreId = new[] { user.StoreId },
TextSearch = invoice.OrderId
}).GetAwaiter().GetResult();
Assert.Single(textSearchResult);
textSearchResult = tester.PayTester.InvoiceRepository.GetInvoices(new InvoiceQuery()
{
StoreId = user.StoreId,
StoreId = new[] { user.StoreId },
TextSearch = invoice.Id
}).GetAwaiter().GetResult();

View File

@ -46,7 +46,7 @@ services:
- lightning-charged
nbxplorer:
image: nicolasdorier/nbxplorer:1.0.2.0
image: nicolasdorier/nbxplorer:1.0.2.2
ports:
- "32838:32838"
expose:
@ -89,7 +89,7 @@ services:
- "bitcoin_datadir:/data"
customer_lightningd:
image: nicolasdorier/clightning:0.0.0.3
image: nicolasdorier/clightning:0.0.0.9-dev
environment:
EXPOSE_TCP: "true"
LIGHTNINGD_OPT: |
@ -98,6 +98,7 @@ services:
network=regtest
ipaddr=customer_lightningd
log-level=debug
dev-broadcast-interval=1000
ports:
- "30992:9835" # api port
expose:
@ -129,7 +130,7 @@ services:
- merchant_lightningd
merchant_lightningd:
image: nicolasdorier/clightning:0.0.0.5-dev
image: nicolasdorier/clightning:0.0.0.9-dev
environment:
EXPOSE_TCP: "true"
LIGHTNINGD_OPT: |

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<Version>1.0.1.91</Version>
<Version>1.0.1.93</Version>
<NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn>
</PropertyGroup>
<ItemGroup>
@ -34,15 +34,15 @@
<PackageReference Include="Hangfire" Version="1.6.19" />
<PackageReference Include="Hangfire.MemoryStorage" Version="1.5.2" />
<PackageReference Include="Hangfire.PostgreSql" Version="1.4.8.1" />
<PackageReference Include="LedgerWallet" Version="1.0.1.35" />
<PackageReference Include="LedgerWallet" Version="1.0.1.36" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.6.1" />
<PackageReference Include="Meziantou.AspNetCore.BundleTagHelpers" Version="1.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" />
<PackageReference Include="Microsoft.NetCore.Analyzers" Version="2.6.0" />
<PackageReference Include="NBitcoin" Version="4.1.1" />
<PackageReference Include="NBitcoin" Version="4.1.1.3" />
<PackageReference Include="NBitpayClient" Version="1.0.0.18" />
<PackageReference Include="DBreeze" Version="1.87.0" />
<PackageReference Include="NBXplorer.Client" Version="1.0.2" />
<PackageReference Include="NBXplorer.Client" Version="1.0.2.3" />
<PackageReference Include="NicolasDorier.CommandLine" Version="1.0.0.1" />
<PackageReference Include="NicolasDorier.CommandLine.Configuration" Version="1.0.0.2" />
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.13" />

View File

@ -42,10 +42,12 @@ namespace BTCPayServer.Controllers
" price: 15\n\n" +
"tshirt:\n" +
" price: 25";
ShowCustomAmount = true;
}
public string Title { get; set; }
public string Currency { get; set; }
public string Template { get; set; }
public bool ShowCustomAmount { get; set; }
}
[HttpGet]
@ -57,7 +59,7 @@ namespace BTCPayServer.Controllers
return NotFound();
var settings = app.GetSettings<PointOfSaleSettings>();
return View(new UpdatePointOfSaleViewModel() { Title = settings.Title, Currency = settings.Currency, Template = settings.Template });
return View(new UpdatePointOfSaleViewModel() { Title = settings.Title, ShowCustomAmount = settings.ShowCustomAmount, Currency = settings.Currency, Template = settings.Template });
}
[HttpPost]
[Route("{appId}/settings/pos")]
@ -83,6 +85,7 @@ namespace BTCPayServer.Controllers
app.SetSettings(new PointOfSaleSettings()
{
Title = vm.Title,
ShowCustomAmount = vm.ShowCustomAmount,
Currency = vm.Currency.ToUpperInvariant(),
Template = vm.Template
});
@ -99,9 +102,13 @@ namespace BTCPayServer.Controllers
if (app == null)
return NotFound();
var settings = app.GetSettings<PointOfSaleSettings>();
var currency = _Currencies.GetCurrencyData(settings.Currency);
double step = currency == null ? 1 : Math.Pow(10, -(currency.Divisibility));
return View(new ViewPointOfSaleViewModel()
{
Title = settings.Title,
Step = step.ToString(CultureInfo.InvariantCulture),
ShowCustomAmount = settings.ShowCustomAmount,
Items = Parse(settings.Template, settings.Currency)
});
}
@ -155,23 +162,43 @@ namespace BTCPayServer.Controllers
[HttpPost]
[Route("{appId}/pos")]
public async Task<IActionResult> ViewPointOfSale(string appId, string choiceKey)
public async Task<IActionResult> ViewPointOfSale(string appId, double amount, string choiceKey)
{
var app = await GetApp(appId, AppType.PointOfSale);
if (string.IsNullOrEmpty(choiceKey) && amount <= 0)
{
return RedirectToAction(nameof(ViewPointOfSale), new { appId = appId });
}
if (app == null)
return NotFound();
var settings = app.GetSettings<PointOfSaleSettings>();
var choices = Parse(settings.Template, settings.Currency);
var choice = choices.FirstOrDefault(c => c.Id == choiceKey);
if (choice == null)
return NotFound();
if(string.IsNullOrEmpty(choiceKey) && !settings.ShowCustomAmount)
{
return RedirectToAction(nameof(ViewPointOfSale), new { appId = appId });
}
string title = null;
double price = 0.0;
if (!string.IsNullOrEmpty(choiceKey))
{
var choices = Parse(settings.Template, settings.Currency);
var choice = choices.FirstOrDefault(c => c.Id == choiceKey);
if (choice == null)
return NotFound();
title = choice.Title;
price = (double)choice.Price.Value;
}
else
{
price = amount;
title = settings.Title;
}
var store = await GetStore(app);
var invoice = await _InvoiceController.CreateInvoiceCore(new NBitpayClient.Invoice()
{
ItemDesc = choice.Title,
ItemDesc = title,
Currency = settings.Currency,
Price = (double)choice.Price.Value,
Price = price,
}, store, HttpContext.Request.GetAbsoluteRoot());
return Redirect(invoice.Data.Url);
}

View File

@ -87,8 +87,8 @@ namespace BTCPayServer.Controllers
StartDate = dateStart,
OrderId = orderId,
ItemCode = itemCode,
Status = status,
StoreId = store.Id
Status = status == null ? null : new[] { status },
StoreId = new[] { store.Id }
};

View File

@ -232,6 +232,7 @@ namespace BTCPayServer.Controllers
OrderAmount = (accounting.TotalDue - accounting.NetworkFee).ToString(),
BtcDue = accounting.Due.ToString(),
CustomerEmail = invoice.RefundMail,
RequiresRefundEmail = storeBlob.RequiresRefundEmail,
ExpirationSeconds = Math.Max(0, (int)(invoice.ExpirationTime - DateTimeOffset.UtcNow).TotalSeconds),
MaxTimeSeconds = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds,
MaxTimeMinutes = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes,
@ -366,8 +367,8 @@ namespace BTCPayServer.Controllers
Count = count,
Skip = skip,
UserId = GetUserId(),
Status = filterString.Filters.TryGet("status"),
StoreId = filterString.Filters.TryGet("storeid")
Status = filterString.Filters.ContainsKey("status") ? filterString.Filters["status"].ToArray() : null,
StoreId = filterString.Filters.ContainsKey("storeid") ? filterString.Filters["storeid"].ToArray() : null
}))
{
model.SearchTerm = searchTerm;

View File

@ -201,6 +201,7 @@ namespace BTCPayServer.Controllers
vm.LightningMaxValue = storeBlob.LightningMaxValue?.ToString() ?? "";
vm.OnChainMinValue = storeBlob.OnChainMinValue?.ToString() ?? "";
vm.AllowCoinConversion = storeBlob.AllowCoinConversion;
vm.RequiresRefundEmail = storeBlob.RequiresRefundEmail;
vm.CustomCSS = storeBlob.CustomCSS?.AbsoluteUri;
vm.CustomLogo = storeBlob.CustomLogo?.AbsoluteUri;
return View(vm);
@ -247,6 +248,7 @@ namespace BTCPayServer.Controllers
}
blob.DefaultLang = model.DefaultLang;
blob.AllowCoinConversion = model.AllowCoinConversion;
blob.RequiresRefundEmail = model.RequiresRefundEmail;
blob.LightningMaxValue = lightningMaxValue;
blob.OnChainMinValue = onchainMinValue;
blob.CustomLogo = string.IsNullOrWhiteSpace(model.CustomLogo) ? null : new Uri(model.CustomLogo, UriKind.Absolute);

View File

@ -214,6 +214,7 @@ namespace BTCPayServer.Data
{
InvoiceExpiration = 15;
MonitoringExpiration = 60;
RequiresRefundEmail = true;
}
public bool NetworkFeeDisabled
{
@ -223,6 +224,9 @@ namespace BTCPayServer.Data
{
get; set;
}
public bool RequiresRefundEmail { get; set; }
public string DefaultLang { get; set; }
[DefaultValue(60)]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]

View File

@ -17,5 +17,8 @@ namespace BTCPayServer.Models.AppViewModels
[Required]
[MaxLength(5000)]
public string Template { get; set; }
[Display(Name = "User can input custom amount")]
public bool ShowCustomAmount { get; set; }
}
}

View File

@ -18,6 +18,8 @@ namespace BTCPayServer.Models.AppViewModels
public ItemPrice Price { get; set; }
public string Title { get; set; }
}
public bool ShowCustomAmount { get; set; }
public string Step { get; set; }
public string Title { get; set; }
public Item[] Items { get; set; }
}

View File

@ -24,6 +24,7 @@ namespace BTCPayServer.Models.InvoicingModels
public string BtcAddress { get; set; }
public string BtcDue { get; set; }
public string CustomerEmail { get; set; }
public bool RequiresRefundEmail { get; set; }
public int ExpirationSeconds { get; set; }
public string Status { get; set; }
public string MerchantRefLink { get; set; }

View File

@ -31,6 +31,12 @@ namespace BTCPayServer.Models.StoreViewModels
[MaxLength(20)]
public string LightningMaxValue { get; set; }
[Display(Name = "Requires a refund email")]
public bool RequiresRefundEmail
{
get; set;
}
[Display(Name = "Do not propose on chain payment if the value of the invoice is below...")]
[MaxLength(20)]
public string OnChainMinValue { get; set; }

View File

@ -1111,4 +1111,17 @@ namespace BTCPayServer
#endregion
}
}
public static class MultiValueDictionaryExtensions
{
public static MultiValueDictionary<TKey, TValue> ToMultiValueDictionary<TInput, TKey, TValue>(this IEnumerable<TInput> collection, Func<TInput, TKey> keySelector, Func<TInput, TValue> valueSelector)
{
var dictionary = new MultiValueDictionary<TKey, TValue>();
foreach(var item in collection)
{
dictionary.Add(keySelector(item), valueSelector(item));
}
return dictionary;
}
}
}

View File

@ -21,7 +21,7 @@ namespace BTCPayServer
.Select(t => t.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries))
.Where(kv => kv.Length == 2)
.Select(kv => new KeyValuePair<string, string>(kv[0].ToLowerInvariant(), kv[1]))
.ToDictionary(o => o.Key, o => o.Value);
.ToMultiValueDictionary(o => o.Key, o => o.Value);
foreach(var filter in splitted)
{
@ -38,8 +38,8 @@ namespace BTCPayServer
get;
private set;
}
public Dictionary<string, string> Filters { get; private set; }
public MultiValueDictionary<string, string> Filters { get; private set; }
public override string ToString()
{

View File

@ -99,10 +99,14 @@ namespace BTCPayServer.Services
try
{
var pubKey = await ledger.GetWalletPubKeyAsync(account);
if (pubKey.Address.Network != network.NBitcoinNetwork)
try
{
pubKey.GetAddress(network.NBitcoinNetwork);
}
catch
{
if (network.NBitcoinNetwork.NetworkType == NetworkType.Mainnet)
throw new Exception($"The opened ledger app should be for {network.NBitcoinNetwork.Name}, not for {pubKey.Address.Network}");
throw new Exception($"The opened ledger app does not seems to support {network.NBitcoinNetwork.Name}.");
}
var fingerprint = onlyChaincode ? new byte[4] : (await ledger.GetWalletPubKeyAsync(account.Parent)).UncompressedPublicKey.Compress().Hash.ToBytes().Take(4).ToArray();
var extpubkey = new ExtPubKey(pubKey.UncompressedPublicKey.Compress(), pubKey.ChainCode, (byte)account.Indexes.Length, fingerprint, account.Indexes.Last()).GetWif(network.NBitcoinNetwork);
@ -195,6 +199,7 @@ namespace BTCPayServer.Services
TransactionBuilder builder = new TransactionBuilder();
builder.StandardTransactionPolicy.MinRelayTxFee = minTxRelayFee;
builder.SetConsensusFactory(network.NBitcoinNetwork);
builder.AddCoins(coins.Select(c=>c.Coin).ToArray());
foreach (var element in send)

View File

@ -399,9 +399,10 @@ namespace BTCPayServer.Services.Invoices
query = query.Where(i => i.Id == queryObject.InvoiceId);
}
if (!string.IsNullOrEmpty(queryObject.StoreId))
if (queryObject.StoreId != null && queryObject.StoreId.Length > 0)
{
query = query.Where(i => i.StoreDataId == queryObject.StoreId);
var stores = queryObject.StoreId.ToHashSet();
query = query.Where(i => stores.Contains(i.StoreDataId));
}
if (queryObject.UserId != null)
@ -429,8 +430,11 @@ namespace BTCPayServer.Services.Invoices
if (queryObject.OrderId != null)
query = query.Where(i => i.OrderId == queryObject.OrderId);
if (queryObject.Status != null)
query = query.Where(i => i.Status == queryObject.Status);
if (queryObject.Status != null && queryObject.Status.Length > 0)
{
var statusSet = queryObject.Status.ToHashSet();
query = query.Where(i => statusSet.Contains(i.Status));
}
query = query.OrderByDescending(q => q.Created);
@ -568,7 +572,7 @@ namespace BTCPayServer.Services.Invoices
public class InvoiceQuery
{
public string StoreId
public string[] StoreId
{
get; set;
}
@ -610,7 +614,7 @@ namespace BTCPayServer.Services.Invoices
get; set;
}
public string Status
public string[] Status
{
get; set;
}

View File

@ -29,6 +29,10 @@
<input asp-for="Currency" class="form-control" />
<span asp-validation-for="Currency" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ShowCustomAmount"></label>
<input asp-for="ShowCustomAmount" type="checkbox" class="form-check" />
</div>
<div class="form-group">
<label asp-for="Template" class="control-label"></label>*
<textarea asp-for="Template" rows="20" cols="40" class="form-control"></textarea>

View File

@ -19,7 +19,7 @@
<h1 class="mb-4">@Model.Title</h1>
<form method="post">
<div class="row">
@foreach (var item in Model.Items)
@foreach(var item in Model.Items)
{
<div class="col-sm-4 mb-3">
<h3>@item.Title</h3>
@ -28,18 +28,20 @@
}
</div>
</form>
@*<div class="row mt-4">
@if(Model.ShowCustomAmount)
{
<div class="row mt-4">
<div class="col-md-4 offset-md-4 col-sm-6 offset-sm-3">
<h3>Something else</h3>
<form data-buy>
<form method="post" data-buy>
<div class="input-group">
<input class="form-control" type="number" step="0.00001" name="amount" placeholder="undefined (optional)"><div class="input-group-append">
<input class="form-control" type="number" min="0" step="@Model.Step" name="amount" placeholder="amount"><div class="input-group-append">
<button class="btn btn-primary" type="submit">Pay</button>
</div>
</div>
</form>
</div>
</div>*@
</div>
}
</div>
</div>
<script src="~/vendor/jquery/jquery.js"></script>

View File

@ -7,6 +7,19 @@
.linethrough {
text-decoration: line-through;
}
.smMaxWidth {
max-width: 200px;
}
@@media (min-width: 768px) {
.smMaxWidth {
max-width: 400px;
}
}
.firstCol {
width: 140px;
}
</style>
<section>
@ -170,12 +183,12 @@
</table>
</div>
</div>
@if(Model.OnChainPayments.Count > 0)
@if (Model.OnChainPayments.Count > 0)
{
<div class="row">
<div class="col-md-12">
<h3>On-Chain payments</h3>
<table class="table table-sm table-responsive-md">
<table class="table table-sm table-responsive-lg">
<thead class="thead-inverse">
<tr>
<th>Crypto</th>
@ -185,13 +198,17 @@
</tr>
</thead>
<tbody>
@foreach(var payment in Model.OnChainPayments)
@foreach (var payment in Model.OnChainPayments)
{
var replaced = payment.Replaced ? "class='linethrough'" : "";
<tr>
<td @replaced>@payment.Crypto</td>
<td @replaced>@payment.DepositAddress</td>
<td @replaced><a href="@payment.TransactionLink" target="_blank">@payment.TransactionId</a></td>
<tr @replaced>
<td>@payment.Crypto</td>
<td>@payment.DepositAddress</td>
<td class="smMaxWidth text-truncate">
<a href="@payment.TransactionLink" target="_blank">
@payment.TransactionId
</a>
</td>
<td class="text-right">@payment.Confirmations</td>
</tr>
}
@ -200,7 +217,7 @@
</div>
</div>
}
@if(Model.OffChainPayments.Count > 0)
@if (Model.OffChainPayments.Count > 0)
{
<div class="row">
<div class="col-md-12">
@ -208,16 +225,16 @@
<table class="table table-sm table-responsive-md">
<thead class="thead-inverse">
<tr>
<th>Crypto</th>
<th class="firstCol">Crypto</th>
<th>BOLT11</th>
</tr>
</thead>
<tbody>
@foreach(var payment in Model.OffChainPayments)
@foreach (var payment in Model.OffChainPayments)
{
<tr>
<td>@payment.Crypto</td>
<td>@payment.BOLT11</td>
<td class="smMaxWidth text-truncate">@payment.BOLT11</td>
</tr>
}
</tbody>
@ -231,17 +248,17 @@
<table class="table table-sm table-responsive-md">
<thead class="thead-inverse">
<tr>
<th>Payment method</th>
<th class="firstCol">Payment method</th>
<th>Address</th>
</tr>
</thead>
<tbody>
@foreach (var address in Model.Addresses)
{
var current = address.Current ? "class='font-weight-bold'" : "";
var current = address.Current ? "font-weight-bold" : "";
<tr>
<td>@address.PaymentMethod</td>
<td @current>@address.Destination</td>
<td class="smMaxWidth text-truncate @current">@address.Destination</td>
</tr>
}
</tbody>

View File

@ -26,6 +26,9 @@
<li><b>storeid:id</b> for filtering a specific store</li>
<li><b>status:(expired|invalid|complete|confirmed|paid|new)</b> for filtering a specific status</li>
</ul>
<p>
If you want two confirmed and complete invoices, duplicate the filter: `status:confirmed status:complete`.
</p>
</div>
<div class="form-group">
<form asp-action="SearchInvoice" method="post">

View File

@ -38,6 +38,10 @@
<label asp-for="AllowCoinConversion"></label>
<input asp-for="AllowCoinConversion" type="checkbox" class="form-check" />
</div>
<div class="form-group">
<label asp-for="RequiresRefundEmail"></label>
<input asp-for="RequiresRefundEmail" type="checkbox" class="form-check" />
</div>
<div class="form-group">
<label asp-for="LightningMaxValue"></label>
<input asp-for="LightningMaxValue" class="form-control" />

View File

@ -104,14 +104,11 @@ $(document).ready(function () {
*/
var display = $(".timer-row__time-left"); // Timer container
// check if the Document expired
if (srvModel.expirationSeconds > 0) {
progressStart(srvModel.maxTimeSeconds); // Progress bar
startTimer(srvModel.expirationSeconds, display); // Timer
if (!validateEmail(srvModel.customerEmail))
if (srvModel.requiresRefundEmail && !validateEmail(srvModel.customerEmail))
emailForm(); // Email form Display
else
hideEmailForm();
@ -246,42 +243,21 @@ $(document).ready(function () {
$(".single-item-order__right__btc-price__chevron").toggleClass("expanded");
});
// Timer Countdown
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
var timeout = setInterval(function () {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.text(minutes + ":" + seconds);
if (--timer < 0) {
clearInterval(timeout);
}
}, 1000);
}
// Progress bar
// Timer Countdown && Progress bar
function progressStart(timerMax) {
var end = new Date(); // Setup Time Variable, should come from server
end.setSeconds(end.getSeconds() + srvModel.expirationSeconds);
timerMax *= 1000; // Usually 15 minutes = 9000 second= 900000 ms
var timeoutVal = Math.floor(timerMax / 100); // Timeout calc
animateUpdate(); //Launch it
function updateProgress(percentage) {
$('.timer-row__progress-bar').css("width", percentage + "%");
}
function animateUpdate() {
var now = new Date();
var timeDiff = end.getTime() - now.getTime();
var perc = 100 - Math.round(timeDiff / timerMax * 100);
var status = checkoutCtrl.srvModel.status;
updateTimer(timeDiff / 1000);
if (perc === 75 && (status === "paidPartial" || status === "new")) {
$(".timer-row").addClass("expiring-soon");
checkoutCtrl.expiringSoon = true;
@ -289,12 +265,34 @@ $(document).ready(function () {
}
if (perc <= 100) {
updateProgress(perc);
var timeoutVal = 300; // Timeout calc
setTimeout(animateUpdate, timeoutVal);
}
//if (perc >= 100 && status === "expired") {
// onDataCallback(status);
//}
}
function updateProgress(percentage) {
$('.timer-row__progress-bar').css("width", percentage + "%");
}
function updateTimer(timer) {
var display = $(".timer-row__time-left");
if (timer >= 0) {
var minutes = parseInt(timer / 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
var seconds = parseInt(timer % 60, 10);
seconds = seconds < 10 ? "0" + seconds : seconds;
display.text(minutes + ":" + seconds);
} else {
display.text("00:00");
}
}
}
// Clipboard Copy

View File

@ -47,5 +47,8 @@ const locales_is = {
"Archived_Body": "Vinsamlegast hafðu samband fyrir upplýsingar eða aðstoð.",
// Lightning
"BOLT 11 Invoice": "BOLT 11 Reikningur",
"Node Info": "Nótu upplýsingar"
"Node Info": "Nótu upplýsingar",
//
"txCount": "{{count}} reikningur",
"txCount_plural": "{{count}} reikningar"
};