mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-20 13:34:37 +01:00
Checkout: Allow NFC/LNURL-W whenever LNURL is available (#4671)
* Checkout: Allow NFC/LNURL-W whenever LNURL is available With what we have in master right now, we display NFC only for top-up invoices. With these changes, we display NFC in all cases, where LNURL is available. Note that this hides LNURL from the list of selectable payment methods, it's only available to use the NFC — and explicitely selectable only for the edge case of top-up invoice + non-unified QR (as before). Rationale: Now that we got NFC tightly integrated, it doesn't make sense to support the NFC experience only for top-up invoices. With this we bring back LNURL for regular invoices as well, but don't make it selectable and use it only for the NFC functionality. * Fix LNURL condition * Improve and test NFC/LNURL display condition Restores what was fixed in #4660. * Fix and test Lightning-only case * Add cache busting for locales
This commit is contained in:
parent
d542a61f5a
commit
d73d0f178f
8 changed files with 86 additions and 39 deletions
|
@ -23,7 +23,7 @@
|
|||
<PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.14" />
|
||||
<PackageReference Include="Selenium.Support" Version="4.1.1" />
|
||||
<PackageReference Include="Selenium.WebDriver" Version="4.1.1" />
|
||||
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="108.0.5359.7100" />
|
||||
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="110.0.5481.7700" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace BTCPayServer.Tests
|
|||
Assert.Contains("LNURL", s.Driver.FindElement(By.CssSelector(".payment-method:nth-child(2)")).Text);
|
||||
var qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
|
||||
var address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
|
||||
var payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||
var payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
|
||||
var copyAddress = s.Driver.FindElement(By.Id("Address_BTC")).GetAttribute("value");
|
||||
Assert.Equal($"bitcoin:{address}", payUrl);
|
||||
Assert.StartsWith("bcrt", s.Driver.FindElement(By.Id("Address_BTC")).GetAttribute("value"));
|
||||
|
@ -70,15 +70,17 @@ namespace BTCPayServer.Tests
|
|||
Assert.Equal(address, copyAddress);
|
||||
Assert.Equal($"bitcoin:{address.ToUpperInvariant()}", qrValue);
|
||||
s.Driver.ElementDoesNotExist(By.Id("Lightning_BTC"));
|
||||
s.Driver.ElementDoesNotExist(By.Id("PayByLNURL"));
|
||||
|
||||
// Switch to LNURL
|
||||
s.Driver.FindElement(By.CssSelector(".payment-method:nth-child(2)")).Click();
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
|
||||
Assert.StartsWith("lightning:lnurl", payUrl);
|
||||
Assert.StartsWith("lnurl", s.Driver.WaitForElement(By.Id("Lightning_BTC")).GetAttribute("value"));
|
||||
s.Driver.ElementDoesNotExist(By.Id("Address_BTC"));
|
||||
s.Driver.FindElement(By.Id("PayByLNURL"));
|
||||
});
|
||||
|
||||
// Default payment method
|
||||
|
@ -91,12 +93,13 @@ namespace BTCPayServer.Tests
|
|||
Assert.Contains("Bitcoin", s.Driver.WaitForElement(By.CssSelector(".payment-method")).Text);
|
||||
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
|
||||
address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
|
||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
|
||||
copyAddress = s.Driver.FindElement(By.Id("Lightning_BTC_LightningLike")).GetAttribute("value");
|
||||
Assert.Equal($"lightning:{address}", payUrl);
|
||||
Assert.Equal(address, copyAddress);
|
||||
Assert.Equal($"lightning:{address.ToUpperInvariant()}", qrValue);
|
||||
s.Driver.ElementDoesNotExist(By.Id("Address_BTC"));
|
||||
s.Driver.FindElement(By.Id("PayByLNURL"));
|
||||
|
||||
// Lightning amount in Sats
|
||||
Assert.Contains("BTC", s.Driver.FindElement(By.Id("AmountDue")).Text);
|
||||
|
@ -198,7 +201,7 @@ namespace BTCPayServer.Tests
|
|||
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
||||
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
|
||||
address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
|
||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
|
||||
var copyAddressOnchain = s.Driver.FindElement(By.Id("Address_BTC")).GetAttribute("value");
|
||||
var copyAddressLightning = s.Driver.FindElement(By.Id("Lightning_BTC")).GetAttribute("value");
|
||||
Assert.StartsWith($"bitcoin:{address}?amount=", payUrl);
|
||||
|
@ -209,6 +212,7 @@ namespace BTCPayServer.Tests
|
|||
Assert.StartsWith("lnbcrt", copyAddressLightning);
|
||||
Assert.StartsWith($"bitcoin:{address.ToUpperInvariant()}?amount=", qrValue);
|
||||
Assert.Contains("&lightning=LNBCRT", qrValue);
|
||||
s.Driver.FindElement(By.Id("PayByLNURL"));
|
||||
|
||||
// BIP21 with LN as default payment method
|
||||
s.GoToHome();
|
||||
|
@ -216,9 +220,10 @@ namespace BTCPayServer.Tests
|
|||
s.GoToInvoiceCheckout(invoiceId);
|
||||
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
|
||||
Assert.StartsWith("bitcoin:", payUrl);
|
||||
Assert.Contains("&lightning=lnbcrt", payUrl);
|
||||
s.Driver.FindElement(By.Id("PayByLNURL"));
|
||||
|
||||
// Ensure LNURL is enabled
|
||||
s.GoToHome();
|
||||
|
@ -233,7 +238,7 @@ namespace BTCPayServer.Tests
|
|||
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
||||
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
|
||||
address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
|
||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
|
||||
copyAddressOnchain = s.Driver.FindElement(By.Id("Address_BTC")).GetAttribute("value");
|
||||
copyAddressLightning = s.Driver.FindElement(By.Id("Lightning_BTC")).GetAttribute("value");
|
||||
Assert.StartsWith($"bitcoin:{address}", payUrl);
|
||||
|
@ -243,6 +248,7 @@ namespace BTCPayServer.Tests
|
|||
Assert.Equal(address, copyAddressOnchain);
|
||||
Assert.StartsWith("lnurl", copyAddressLightning);
|
||||
Assert.StartsWith($"bitcoin:{address.ToUpperInvariant()}?lightning=LNURL", qrValue);
|
||||
s.Driver.FindElement(By.Id("PayByLNURL"));
|
||||
|
||||
// Expiry message should not show amount for topup invoice
|
||||
expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
|
||||
|
@ -282,6 +288,26 @@ namespace BTCPayServer.Tests
|
|||
Assert.True(paymentInfo.Displayed);
|
||||
Assert.Contains("This invoice will expire in", paymentInfo.Text);
|
||||
Assert.Contains("09:5", paymentInfo.Text);
|
||||
|
||||
// Disable LNURL again
|
||||
s.GoToHome();
|
||||
s.GoToLightningSettings();
|
||||
s.Driver.SetCheckbox(By.Id("LNURLEnabled"), false);
|
||||
s.Driver.FindElement(By.Id("save")).Click();
|
||||
Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text);
|
||||
|
||||
// Test:
|
||||
// - NFC/LNURL-W available with just Lightning
|
||||
// - BIP21 works correctly even though Lightning is default payment method
|
||||
s.GoToHome();
|
||||
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC_LightningLike");
|
||||
s.GoToInvoiceCheckout(invoiceId);
|
||||
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
||||
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
|
||||
Assert.StartsWith("bitcoin:", payUrl);
|
||||
Assert.Contains("&lightning=lnbcrt", payUrl);
|
||||
s.Driver.FindElement(By.Id("PayByLNURL"));
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
|
|
|
@ -652,17 +652,19 @@ namespace BTCPayServer.Controllers
|
|||
var lnurlId = PaymentMethodId.Parse("BTC_LNURLPAY");
|
||||
if (paymentMethodId is null)
|
||||
{
|
||||
var enabledPaymentIds = store.GetEnabledPaymentIds(_NetworkProvider)
|
||||
.Where(pmId => storeBlob.CheckoutType == CheckoutType.V1 ||
|
||||
// Exclude LNURL for Checkout v2 + non-top up invoices
|
||||
pmId != lnurlId || invoice.IsUnsetTopUp())
|
||||
.ToArray();
|
||||
var enabledPaymentIds = store.GetEnabledPaymentIds(_NetworkProvider).ToArray();
|
||||
|
||||
// Exclude Lightning if OnChainWithLnInvoiceFallback is active and we have both payment methods
|
||||
if (storeBlob is { CheckoutType: CheckoutType.V2, OnChainWithLnInvoiceFallback: true } &&
|
||||
enabledPaymentIds.Contains(btcId) && enabledPaymentIds.Contains(lnId))
|
||||
if (storeBlob is { CheckoutType: CheckoutType.V2, OnChainWithLnInvoiceFallback: true })
|
||||
{
|
||||
enabledPaymentIds = enabledPaymentIds.Where(pmId => pmId != lnId).ToArray();
|
||||
if (enabledPaymentIds.Contains(btcId) && enabledPaymentIds.Contains(lnId))
|
||||
{
|
||||
enabledPaymentIds = enabledPaymentIds.Where(pmId => pmId != lnId).ToArray();
|
||||
}
|
||||
if (enabledPaymentIds.Contains(btcId) && enabledPaymentIds.Contains(lnurlId))
|
||||
{
|
||||
enabledPaymentIds = enabledPaymentIds.Where(pmId => pmId != lnurlId).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
PaymentMethodId? invoicePaymentId = invoice.GetDefaultPaymentMethod();
|
||||
|
@ -688,7 +690,7 @@ namespace BTCPayServer.Controllers
|
|||
if (paymentMethodId is null)
|
||||
{
|
||||
paymentMethodId = enabledPaymentIds.FirstOrDefault(e => e.CryptoCode == _NetworkProvider.DefaultNetwork.CryptoCode && e.PaymentType == PaymentTypes.BTCLike) ??
|
||||
enabledPaymentIds.FirstOrDefault(e => e.CryptoCode == _NetworkProvider.DefaultNetwork.CryptoCode && e.PaymentType == PaymentTypes.LightningLike) ??
|
||||
enabledPaymentIds.FirstOrDefault(e => e.CryptoCode == _NetworkProvider.DefaultNetwork.CryptoCode && e.PaymentType != PaymentTypes.LNURLPay) ??
|
||||
enabledPaymentIds.FirstOrDefault();
|
||||
}
|
||||
isDefaultPaymentId = true;
|
||||
|
@ -703,7 +705,12 @@ namespace BTCPayServer.Controllers
|
|||
return null;
|
||||
var paymentMethodTemp = invoice
|
||||
.GetPaymentMethods()
|
||||
.FirstOrDefault(c => paymentMethodId.CryptoCode == c.GetId().CryptoCode);
|
||||
.FirstOrDefault(pm =>
|
||||
{
|
||||
var pmId = pm.GetId();
|
||||
return paymentMethodId.CryptoCode == pmId.CryptoCode &&
|
||||
((invoice.IsUnsetTopUp() && !storeBlob.OnChainWithLnInvoiceFallback) || pmId != lnurlId);
|
||||
});
|
||||
if (paymentMethodTemp == null)
|
||||
paymentMethodTemp = invoice.GetPaymentMethods().FirstOrDefault();
|
||||
if (paymentMethodTemp is null)
|
||||
|
@ -768,6 +775,7 @@ namespace BTCPayServer.Controllers
|
|||
BrandColor = storeBlob.BrandColor,
|
||||
CheckoutType = invoice.CheckoutType ?? storeBlob.CheckoutType,
|
||||
HtmlTitle = storeBlob.HtmlTitle ?? "BTCPay Invoice",
|
||||
OnChainWithLnInvoiceFallback = storeBlob.OnChainWithLnInvoiceFallback,
|
||||
CryptoImage = Request.GetRelativePathOrAbsolute(paymentMethodHandler.GetCryptoImage(paymentMethodId)),
|
||||
BtcAddress = paymentMethodDetails.GetPaymentDestination(),
|
||||
BtcDue = accounting.Due.ShowMoney(divisibility),
|
||||
|
@ -803,9 +811,6 @@ namespace BTCPayServer.Controllers
|
|||
IsMultiCurrency = invoice.GetPayments(false).Select(p => p.GetPaymentMethodId()).Concat(new[] { paymentMethod.GetId() }).Distinct().Count() > 1,
|
||||
StoreId = store.Id,
|
||||
AvailableCryptos = invoice.GetPaymentMethods()
|
||||
.Where(i => i.Network != null && storeBlob.CheckoutType == CheckoutType.V1 ||
|
||||
// Exclude LNURL for Checkout v2 + non-top up invoices
|
||||
i.GetId() != lnurlId || invoice.IsUnsetTopUp())
|
||||
.Select(kv =>
|
||||
{
|
||||
var availableCryptoPaymentMethodId = kv.GetId();
|
||||
|
@ -835,20 +840,16 @@ namespace BTCPayServer.Controllers
|
|||
{
|
||||
var onchainPM = model.AvailableCryptos.Find(c => c.PaymentMethodId == btcId.ToString());
|
||||
var lightningPM = model.AvailableCryptos.Find(c => c.PaymentMethodId == lnId.ToString());
|
||||
var lnurlPM = model.AvailableCryptos.Find(c => c.PaymentMethodId == lnurlId.ToString());
|
||||
if (onchainPM != null && lightningPM != null)
|
||||
{
|
||||
model.AvailableCryptos.Remove(lightningPM);
|
||||
}
|
||||
if (onchainPM != null && lnurlPM != null)
|
||||
{
|
||||
model.AvailableCryptos.Remove(lnurlPM);
|
||||
}
|
||||
}
|
||||
|
||||
paymentMethodHandler.PreparePaymentModel(model, dto, storeBlob, paymentMethod);
|
||||
model.UISettings = paymentMethodHandler.GetCheckoutUISettings();
|
||||
model.PaymentMethodId = paymentMethodId.ToString();
|
||||
model.PaymentType = paymentMethodId.PaymentType.ToString();
|
||||
var expiration = TimeSpan.FromSeconds(model.ExpirationSeconds);
|
||||
model.TimeLeft = expiration.PrettyPrint();
|
||||
return model;
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace BTCPayServer.Models.InvoicingModels
|
|||
public List<AvailableCrypto> AvailableCryptos { get; set; } = new();
|
||||
public bool IsModal { get; set; }
|
||||
public bool IsUnsetTopUp { get; set; }
|
||||
public bool OnChainWithLnInvoiceFallback { get; set; }
|
||||
public string CryptoCode { get; set; }
|
||||
public string InvoiceId { get; set; }
|
||||
public string BtcAddress { get; set; }
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
</div>
|
||||
<button type="button" class="btn btn-link" data-clipboard-target="#Lightning_@Model.PaymentMethodId" :data-clipboard-confirm="$t('copy_confirm')" v-t="'copy'"></button>
|
||||
</div>
|
||||
<a v-if="model.invoiceBitcoinUrl" class="btn btn-primary rounded-pill w-100 mt-4" target="_top"
|
||||
<a v-if="model.invoiceBitcoinUrl" class="btn btn-primary rounded-pill w-100 mt-4" target="_top" id="PayInWallet"
|
||||
:href="model.invoiceBitcoinUrl" :title="$t(hasPayjoin ? 'BIP21 payment link with PayJoin support' : 'BIP21 payment link')" v-t="'pay_in_wallet'"></a>
|
||||
@await Component.InvokeAsync("UiExtensionPoint", new {location = "checkout-v2-bitcoin-post-content", model = Model})
|
||||
</div>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</div>
|
||||
<button type="button" class="btn btn-link" data-clipboard-target="#Lightning_@Model.PaymentMethodId" :data-clipboard-confirm="$t('copy_confirm')" v-t="'copy'"></button>
|
||||
</div>
|
||||
<a v-if="model.invoiceBitcoinUrl" class="btn btn-primary rounded-pill w-100 mt-4" target="_top"
|
||||
<a v-if="model.invoiceBitcoinUrl" class="btn btn-primary rounded-pill w-100 mt-4" target="_top" id="PayInWallet"
|
||||
:href="model.invoiceBitcoinUrl" v-t="'pay_in_wallet'"></a>
|
||||
@await Component.InvokeAsync("UiExtensionPoint", new {location = "checkout-v2-lightning-post-content", model = Model})
|
||||
</div>
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
<template id="lnurl-withdraw-template">
|
||||
<template v-if="display">
|
||||
<button v-if="isV2" class="btn btn-secondary rounded-pill w-100 mt-4" type="button"
|
||||
v-on:click="startScan"
|
||||
v-bind:disabled="scanning || submitting"
|
||||
v-bind:class="{ 'loading': scanning || submitting, 'text-secondary': !supported }">{{btnText}}</button>
|
||||
:disabled="scanning || submitting" v-on:click="startScan" :id="btnId"
|
||||
:class="{ 'loading': scanning || submitting, 'text-secondary': !supported }">{{btnText}}</button>
|
||||
<bp-loading-button v-else>
|
||||
<button v-on:click="startScan" class="action-button" style="margin: 0 45px;width:calc(100% - 90px) !important" v-bind:disabled="scanning || submitting"
|
||||
v-bind:class="{ 'loading': scanning || submitting, 'action-button': supported, 'btn btn-text w-100': !supported }">
|
||||
<button class="action-button" style="margin: 0 45px;width:calc(100% - 90px) !important"
|
||||
:disabled="scanning || submitting" v-on:click="startScan" :id="btnId"
|
||||
:class="{ 'loading': scanning || submitting, 'action-button': supported, 'btn btn-text w-100': !supported }">
|
||||
<span class="button-text">{{btnText}}</span>
|
||||
<div class="loader-wrapper">
|
||||
@await Html.PartialAsync("~/Views/UIInvoice/Checkout-Spinner.cshtml")
|
||||
|
@ -26,9 +26,25 @@ Vue.component("lnurl-withdraw-checkout", {
|
|||
},
|
||||
computed: {
|
||||
display: function () {
|
||||
return (
|
||||
this.model.paymentMethodId === 'BTC_LNURLPAY' || (
|
||||
this.model.paymentMethodId === 'BTC' && this.model.invoiceBitcoinUrl.match(/lightning=lnurl/i)));
|
||||
const {
|
||||
onChainWithLnInvoiceFallback: isUnified,
|
||||
paymentMethodId: activePaymentMethodId,
|
||||
availableCryptos: availablePaymentMethods,
|
||||
invoiceBitcoinUrl: paymentUrl
|
||||
} = this.model
|
||||
const lnurlwAvailable =
|
||||
// Either we have LN or LNURL available directly
|
||||
!!availablePaymentMethods.find(pm => ['BTC_LNURLPAY', 'BTC_LightningLike'].includes(pm.paymentMethodId)) ||
|
||||
// Or the BIP21 payment URL flags Lightning support
|
||||
!!paymentUrl.match(/lightning=ln/i)
|
||||
return activePaymentMethodId === 'BTC_LNURLPAY' || (
|
||||
// Unified QR/BIP21 case
|
||||
(activePaymentMethodId === 'BTC' && isUnified && lnurlwAvailable) ||
|
||||
// Lightning with LNURL available
|
||||
(activePaymentMethodId === 'BTC_LightningLike' && lnurlwAvailable))
|
||||
},
|
||||
btnId: function () {
|
||||
return this.supported ? 'PayByNFC' : 'PayByLNURL'
|
||||
},
|
||||
btnText: function () {
|
||||
if (this.supported) {
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
ViewData["Title"] = Model.HtmlTitle;
|
||||
|
||||
var hasPaymentPlugins = UiExtensions.Any(extension => extension.Location == "checkout-payment-method");
|
||||
var paymentMethodCount = Model.AvailableCryptos.Count;
|
||||
// Show LNURL as selectable payment method only for top up invoices + non-BIP21 case
|
||||
var displayedPaymentMethods = Model.IsUnsetTopUp && !Model.OnChainWithLnInvoiceFallback
|
||||
? Model.AvailableCryptos
|
||||
: Model.AvailableCryptos.Where(c => c.PaymentMethodId != "BTC_LNURLPAY").ToList();
|
||||
}
|
||||
@functions {
|
||||
private string PaymentMethodName(PaymentModel.AvailableCrypto pm)
|
||||
|
@ -73,12 +76,12 @@
|
|||
<div id="PaymentDetails" class="payment-details" v-collapsible="displayPaymentDetails">
|
||||
<payment-details :srv-model="srvModel" :is-active="isActive" class="pb-4"></payment-details>
|
||||
</div>
|
||||
@if (paymentMethodCount > 1 || hasPaymentPlugins)
|
||||
@if (displayedPaymentMethods.Count > 1 || hasPaymentPlugins)
|
||||
{
|
||||
<div class="mt-3 mb-2">
|
||||
<h6 class="text-center mb-3" v-t="'pay_with'"></h6>
|
||||
<div class="btcpay-pills d-flex flex-wrap align-items-center justify-content-center gap-2 pb-2">
|
||||
@foreach (var crypto in Model.AvailableCryptos)
|
||||
@foreach (var crypto in displayedPaymentMethods)
|
||||
{
|
||||
<a asp-action="Checkout" asp-route-invoiceId="@Model.InvoiceId" asp-route-paymentMethodId="@crypto.PaymentMethodId"
|
||||
class="btcpay-pill m-0 payment-method"
|
||||
|
@ -210,7 +213,7 @@
|
|||
</div>
|
||||
</dl>
|
||||
<script>
|
||||
const i18nUrl = @Safe.Json($"{Model.RootPath}locales/checkout/{{{{lng}}}}.json");
|
||||
const i18nUrl = @Safe.Json($"{Model.RootPath}locales/checkout/{{{{lng}}}}.json?v={Env.Version}");
|
||||
const statusUrl = @Safe.Json(Url.Action("GetStatus", new { invoiceId = Model.InvoiceId }));
|
||||
const statusWsUrl = @Safe.Json(Url.Action("GetStatusWebSocket", new { invoiceId = Model.InvoiceId }));
|
||||
const availableLanguages = ['en']; // @Safe.Json(LangService.GetLanguages().Select(language => language.Code));
|
||||
|
|
Loading…
Add table
Reference in a new issue