Point of Sale: Improve merchant view (#4560)

* Point of Sale: Improve merchant view

Closes #3843.

* Trim bottom section

* Display App Name and Display Title next to each other

* Update views
This commit is contained in:
d11n 2023-01-26 01:27:31 +01:00 committed by GitHub
parent 5089ec9826
commit 69e90b7ff1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 289 additions and 266 deletions

View file

@ -782,6 +782,7 @@ namespace BTCPayServer.Tests
s.Driver.FindElement(By.Id("Create")).Click();
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
s.Driver.FindElement(By.CssSelector("label[for='DefaultView_Cart']")).Click();
s.Driver.FindElement(By.CssSelector(".template-item:nth-of-type(1) .btn-primary")).Click();
s.Driver.FindElement(By.Id("BuyButtonText")).SendKeys("Take my money");
s.Driver.FindElement(By.Id("SaveItemChanges")).Click();
@ -790,7 +791,6 @@ namespace BTCPayServer.Tests
var template = s.Driver.FindElement(By.Id("Template")).GetAttribute("value");
Assert.Contains("buyButtonText: Take my money", template);
s.Driver.FindElement(By.Id("DefaultView")).SendKeys("Item list and cart");
s.Driver.FindElement(By.Id("SaveSettings")).Click();
Assert.Contains("App updated", s.FindAlertMessage().Text);
@ -1796,8 +1796,7 @@ namespace BTCPayServer.Tests
s.Driver.FindElement(By.Id("AppName")).SendKeys(Guid.NewGuid().ToString());
s.Driver.FindElement(By.Id("Create")).Click();
TestUtils.Eventually(() => Assert.Contains("App successfully created", s.FindAlertMessage().Text));
s.Driver.FindElement(By.Id("DefaultView")).Click();
s.Driver.FindElement(By.CssSelector("option[value='3']")).Click();
s.Driver.FindElement(By.CssSelector("label[for='DefaultView_Print']")).Click();
s.Driver.FindElement(By.Id("SaveSettings")).Click();
Assert.Contains("App updated", s.FindAlertMessage().Text);

View file

@ -352,7 +352,6 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
RedirectUrl = settings.RedirectUrl,
SearchTerm = app.TagAllInvoices ? $"storeid:{app.StoreDataId}" : $"orderid:{AppService.GetAppOrderId(app)}",
RedirectAutomatically = settings.RedirectAutomatically.HasValue ? settings.RedirectAutomatically.Value ? "true" : "false" : "",
RequiresRefundEmail = settings.RequiresRefundEmail,
FormId = settings.FormId
};
if (HttpContext?.Request != null)
@ -440,8 +439,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
Description = vm.Description,
EmbeddedCSS = vm.EmbeddedCSS,
RedirectAutomatically =
string.IsNullOrEmpty(vm.RedirectAutomatically) ? (bool?)null : bool.Parse(vm.RedirectAutomatically),
RequiresRefundEmail = vm.RequiresRefundEmail
string.IsNullOrEmpty(vm.RedirectAutomatically) ? (bool?)null : bool.Parse(vm.RedirectAutomatically)
};
settings.FormId = vm.FormId;

View file

@ -99,10 +99,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Models
public string EmbeddedCSS { get; set; }
public string Description { get; set; }
[Display(Name = "Require refund email on checkout")]
public RequiresRefundEmail RequiresRefundEmail { get; set; } = RequiresRefundEmail.InheritFromStore;
[Display(Name = "Request customer data on checkout")]
public string FormId { get; set; } = null;
public string FormId { get; set; }
}
}

View file

@ -11,12 +11,13 @@ namespace BTCPayServer.Services.Apps
public enum PosViewType
{
[Display(Name = "Item list only")]
[Display(Name = "Product list")]
Static,
[Display(Name = "Item list and cart")]
[Display(Name = "Product list with cart")]
Cart,
[Display(Name = "Keypad only")]
Light,
[Display(Name = "Print display")]
Print
}

View file

@ -42,44 +42,49 @@
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div class="form-group">
<label asp-for="AppName" class="form-label" data-required></label>
<input asp-for="AppName" class="form-control" required />
<span asp-validation-for="AppName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Title" class="form-label" data-required></label>
<input asp-for="Title" class="form-control" required />
<span asp-validation-for="Title" class="text-danger"></span>
<div class="col-sm-10 col-md-9 col-xl-7 col-xxl-6">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label asp-for="AppName" class="form-label" data-required></label>
<input asp-for="AppName" class="form-control" required />
<span asp-validation-for="AppName" class="text-danger"></span>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label asp-for="Title" class="form-label" data-required></label>
<input asp-for="Title" class="form-control" required />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
</div>
</div>
<div class="form-group">
<label asp-for="Tagline" class="form-label"></label>
<input asp-for="Tagline" class="form-control" />
<span asp-validation-for="Tagline" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-xl-10 col-xxl-constrain">
<div class="form-group">
<label asp-for="Description" class="form-label" data-required></label>
<textarea asp-for="Description" rows="20" cols="40" class="form-control richtext"></textarea>
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<div class="d-flex align-items-center">
<input asp-for="Enabled" type="checkbox" class="btcpay-toggle me-3"/>
<div>
<label asp-for="Enabled" class="form-label mb-0"></label>
<span asp-validation-for="Enabled" class="text-danger"></span>
<div class="text-muted" hidden="@Model.Enabled">The crowdfund is only visible to you. To make it visible to anyone else, enable this.</div>
<div class="text-muted" hidden="@(!Model.Enabled)">The crowdfund is visible to anyone. To make it only visible to you, disable this.</div>
<div class="text-muted">The crowdfund will be visible to anyone.</div>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-xl-10 col-xxl-constrain">
<div class="form-group">
<label asp-for="Description" class="form-label" data-required></label>
<textarea asp-for="Description" rows="20" cols="40" class="form-control richtext"></textarea>
<span asp-validation-for="Description" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-xl-10 col-xxl-constrain">
<h3 class="mt-5 mb-4">Goal</h3>

View file

@ -38,77 +38,89 @@
</a>
</div>
}
else
{
if (Model.ShowCustomAmount)
{
Model.Items = Model.Items.Concat(new[]
<div class="container d-flex">
<div class="justify-content-center align-self-center text-center mx-auto px-2 py-5 w-100 m-auto">
<h1 class="mb-4">@Model.Title</h1>
@if (!string.IsNullOrEmpty(Model.Description))
{
new ViewPointOfSaleViewModel.Item()
{
Description = "Create invoice to pay custom amount",
Title = "Custom amount",
BuyButtonText = Model.CustomButtonText,
Price = new ViewPointOfSaleViewModel.Item.ItemPrice()
{
Type = ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Topup,
}
}
}).ToArray();
}
<div class="alert alert-info alert-dismissible d-flex align-items-center justify-content-center sticky-top mb-0 rounded-0 d-print-none fade show" role="alert">
<button type="button" class="btn btn-info me-4 border border-light" onclick="window.print()">
<i class="fa fa-print"></i>&nbsp;Print
</button>
This view is intended for printing only —
<a asp-route-viewType="static" class="alert-link">Regular version</a>
</div>
}
<div class="container text-center">
@for (int x = 0; x < Model.Items.Length; x++)
{
var item = Model.Items[x];
<div class="card" data-id="@x">
<div class="card-body my-auto">
<h4 class="card-title text-center">@item.Title</h4>
@if (!string.IsNullOrEmpty(item.Description))
{
<p class="card-title text-center">@item.Description</p>
}
<div class="w-100 mb-3 fs-5 text-center">
@switch (item.Price.Type)
{
case ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Topup:
<span>Any amount</span>
break;
case ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Minimum:
<span>@item.Price.Formatted minimum</span>
break;
case ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Fixed:
@item.Price.Formatted
break;
default:
throw new ArgumentOutOfRangeException();
}
</div>
@if (!item.Inventory.HasValue || item.Inventory.Value > 0)
{
if (supported != null)
{
var lnurlEndpoint = new Uri(Url.Action("GetLNURLForApp", "UILNURL", new
{
cryptoCode = supported.CryptoCode,
appid = Model.AppId,
ItemCode = item.Id
}, Context.Request.Scheme, Context.Request.Host.ToString()));
var lnUrl = LNURL.EncodeUri(lnurlEndpoint, "payRequest", supported.UseBech32Scheme);
<a href="@lnUrl" rel="noreferrer noopener"><vc:qr-code data="@lnUrl.ToString().ToUpperInvariant()" /></a>
}
}
<div class="row">
<div class="overflow-hidden col-12">@Safe.Raw(Model.Description)</div>
</div>
}
@if (supported is not null)
{
if (Model.ShowCustomAmount)
{
Model.Items = Model.Items.Concat(new[]
{
new ViewPointOfSaleViewModel.Item()
{
Description = "Create invoice to pay custom amount",
Title = "Custom amount",
BuyButtonText = Model.CustomButtonText,
Price = new ViewPointOfSaleViewModel.Item.ItemPrice()
{
Type = ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Topup,
}
}
}).ToArray();
}
<div class="alert alert-info alert-dismissible d-flex align-items-center justify-content-center sticky-top mb-0 rounded-0 d-print-none fade show" role="alert">
<button type="button" class="btn btn-info me-4 border border-light" onclick="window.print()">
<i class="fa fa-print"></i>&nbsp;Print
</button>
This view is intended for printing only —
<a asp-route-viewType="static" class="alert-link">Regular version</a>
</div>
}
<div class="container text-center">
@for (int x = 0; x < Model.Items.Length; x++)
{
var item = Model.Items[x];
<div class="card" data-id="@x">
<div class="card-body my-auto">
<h4 class="card-title text-center">@item.Title</h4>
@if (!string.IsNullOrEmpty(item.Description))
{
<p class="card-title text-center">@item.Description</p>
}
<div class="w-100 mb-3 fs-5 text-center">
@switch (item.Price.Type)
{
case ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Topup:
<span>Any amount</span>
break;
case ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Minimum:
<span>@item.Price.Formatted minimum</span>
break;
case ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Fixed:
@item.Price.Formatted
break;
default:
throw new ArgumentOutOfRangeException();
}
</div>
@if (!item.Inventory.HasValue || item.Inventory.Value > 0)
{
if (supported != null)
{
var lnurlEndpoint = new Uri(Url.Action("GetLNURLForApp", "UILNURL", new
{
cryptoCode = supported.CryptoCode,
appid = Model.AppId,
ItemCode = item.Id
}, Context.Request.Scheme, Context.Request.Host.ToString()));
var lnUrl = LNURL.EncodeUri(lnurlEndpoint, "payRequest", supported.UseBech32Scheme);
<a href="@lnUrl" rel="noreferrer noopener"><vc:qr-code data="@lnUrl.ToString().ToUpperInvariant()" /></a>
}
}
</div>
</div>
}
</div>
}
</div>
</div>

View file

@ -26,18 +26,37 @@
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div class="form-group">
<label asp-for="AppName" class="form-label" data-required></label>
<input asp-for="AppName" class="form-control" required />
<span asp-validation-for="AppName" class="text-danger"></span>
<div class="col-sm-10 col-md-9 col-xl-7 col-xxl-6">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label asp-for="AppName" class="form-label" data-required></label>
<input asp-for="AppName" class="form-control" required />
<span asp-validation-for="AppName" class="text-danger"></span>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label asp-for="Title" class="form-label" data-required></label>
<input asp-for="Title" class="form-control" required />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
</div>
</div>
<div class="form-group">
<label asp-for="Title" class="form-label" data-required></label>
<input asp-for="Title" class="form-control" required />
<span asp-validation-for="Title" class="text-danger"></span>
<label asp-for="DefaultView" class="form-label" data-required>Choose Point of Sale Style</label>
<div class="btcpay-list-select">
@foreach (var type in Enum.GetValues<PosViewType>())
{
<input type="radio" asp-for="DefaultView" value="@type" id="DefaultView_@type">
<label for="DefaultView_@type" class="btcpay-list-select-item">
<vc:icon symbol="pos-@type.ToString().ToLowerInvariant()" />
@typeof(PosViewType).DisplayName(type.ToString())
</label>
}
</div>
</div>
<div class="form-group">
<div class="form-group mb-0">
<label asp-for="Currency" class="form-label"></label>
<input asp-for="Currency" class="form-control w-auto" currency-selection />
<div class="form-text">Uses the store's default currency (@Model.StoreDefaultCurrency) if empty.</div>
@ -45,7 +64,7 @@
</div>
</div>
</div>
<div class="row">
<div id="description" class="row mt-4">
<div class="col-xl-10 col-xxl-constrain">
<div class="form-group mb-0">
<label asp-for="Description" class="form-label"></label>
@ -54,46 +73,59 @@
</div>
</div>
</div>
<div class="row">
<div class="col-xxl-constrain">
<partial name="TemplateEditor" model="@(nameof(Model.Template), "Products", Model.Currency ?? Model.StoreDefaultCurrency)" />
<div id="products">
<div class="row">
<div class="col-xxl-constrain">
<partial name="TemplateEditor" model="@(nameof(Model.Template), "Products", Model.Currency ?? Model.StoreDefaultCurrency)" />
</div>
</div>
</div>
<div class="row collapse" id="RawEditor">
<div class="col-xxl-constrain">
<div class="form-group pt-3">
<label asp-for="Template" class="form-label"></label>
<textarea asp-for="Template" rows="10" cols="40" class="form-control"></textarea>
<span asp-validation-for="Template" class="text-danger"></span>
<div class="row collapse" id="RawEditor">
<div class="col-xxl-constrain">
<div class="form-group pt-3">
<label asp-for="Template" class="form-label"></label>
<textarea asp-for="Template" rows="10" cols="40" class="form-control"></textarea>
<span asp-validation-for="Template" class="text-danger"></span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<h3 class="mt-5 mb-4">Appearance</h3>
<div class="form-group">
<label asp-for="DefaultView" class="form-label" data-required></label>
<select asp-for="DefaultView" asp-items="@Html.GetEnumSelectList<PosViewType>()" class="form-select" required></select>
<span asp-validation-for="DefaultView" class="text-danger"></span>
<div class="form-text">Choose the point of sale style for your customers.</div>
</div>
<div class="form-group" id="button-price-text">
<label asp-for="ButtonText" class="form-label" data-required></label>
<input asp-for="ButtonText" class="form-control" required />
<span asp-validation-for="ButtonText" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FormId" class="form-label"></label>
<select asp-for="FormId" class="form-select w-auto" asp-items="@checkoutFormOptions"></select>
<span asp-validation-for="FormId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="RequiresRefundEmail" class="form-label"></label>
<select asp-for="RequiresRefundEmail" asp-items="@Html.GetEnumSelectList<RequiresRefundEmail>()" class="form-select w-auto"></select>
<span asp-validation-for="RequiresRefundEmail" class="text-danger"></span>
</div>
<section id="discounts" class="p-0">
<h3 class="mt-5 mb-4">Discounts</h3>
<div class="row mt-5">
<div class="col-sm-10 col-md-9 col-xl-7 col-xxl-6">
<h3 class="mb-4">Checkout</h3>
<fieldset>
<div class="form-group" id="button-price-text">
<label asp-for="ButtonText" class="form-label" data-required></label>
<input asp-for="ButtonText" class="form-control" required />
<span asp-validation-for="ButtonText" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FormId" class="form-label"></label>
<select asp-for="FormId" class="form-select w-auto" asp-items="@checkoutFormOptions"></select>
<span asp-validation-for="FormId" class="text-danger"></span>
</div>
</fieldset>
<fieldset id="tips" class="mt-2">
<legend class="h5 mb-3 fw-semibold">Tips</legend>
<div class="form-group d-flex align-items-center pt-2">
<input asp-for="EnableTips" type="checkbox" class="btcpay-toggle me-3" data-bs-toggle="collapse" data-bs-target="#CustomTipsSettings" aria-expanded="@Model.EnableTips" aria-controls="CustomTipsSettings" />
<label asp-for="EnableTips" class="form-label mb-0"></label>
<span asp-validation-for="EnableTips" class="text-danger"></span>
</div>
<div class="collapse @(Model.EnableTips ? "show" : "")" id="CustomTipsSettings">
<div class="form-group">
<label asp-for="CustomTipText" class="form-label" data-required></label>
<input asp-for="CustomTipText" class="form-control" required />
<span asp-validation-for="CustomTipText" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CustomTipPercentages" class="form-label"></label>
<input asp-for="CustomTipPercentages" class="form-control" />
<span asp-validation-for="CustomTipPercentages" class="text-danger"></span>
</div>
</div>
</fieldset>
<fieldset id="discounts" class="mt-2">
<legend class="h5 mb-3 fw-semibold">Discounts</legend>
<div class="form-group d-flex align-items-center">
<input asp-for="ShowDiscount" type="checkbox" class="btcpay-toggle me-3" />
<div>
@ -102,47 +134,27 @@
</div>
<span asp-validation-for="ShowDiscount" class="text-danger"></span>
</div>
</section>
<section id="custom-payments" class="p-0">
<h3 class="mt-5 mb-4">Custom Payments</h3>
</fieldset>
<fieldset id="custom-payments" class="mt-2">
<legend class="h5 mb-3 fw-semibold">Custom Payments</legend>
<div class="form-group mb-4 d-flex align-items-center">
<input asp-for="ShowCustomAmount" type="checkbox" class="btcpay-toggle me-3" data-bs-toggle="collapse" data-bs-target="#CustomAmountSettings" aria-expanded="@Model.ShowCustomAmount" aria-controls="CustomAmountSettings"/>
<label asp-for="ShowCustomAmount" class="form-label mb-0"></label>
<span asp-validation-for="ShowCustomAmount" class="text-danger"></span>
</div>
<div class="collapse @(Model.ShowCustomAmount ? "show" : "")" id="CustomAmountSettings">
<div class="form-group mb-0 pb-3">
<div class="form-group">
<label asp-for="CustomButtonText" class="form-label" data-required></label>
<input asp-for="CustomButtonText" class="form-control" required />
<span asp-validation-for="CustomButtonText" class="text-danger"></span>
</div>
</div>
</section>
<section id="tips" class="p-0">
<h3 class="mt-5 mb-4">Tips</h3>
<div class="form-group d-flex align-items-center">
<input asp-for="EnableTips" type="checkbox" class="btcpay-toggle me-3" data-bs-toggle="collapse" data-bs-target="#CustomTipsSettings" aria-expanded="@Model.EnableTips" aria-controls="CustomTipsSettings" />
<label asp-for="EnableTips" class="form-label mb-0"></label>
<span asp-validation-for="EnableTips" class="text-danger"></span>
</div>
<div class="collapse @(Model.EnableTips ? "show" : "")" id="CustomTipsSettings">
<div class="form-group pt-3">
<label asp-for="CustomTipText" class="form-label" data-required></label>
<input asp-for="CustomTipText" class="form-control" required />
<span asp-validation-for="CustomTipText" class="text-danger"></span>
</div>
<div class="form-group mb-0">
<label asp-for="CustomTipPercentages" class="form-label"></label>
<input asp-for="CustomTipPercentages" class="form-control" />
<span asp-validation-for="CustomTipPercentages" class="text-danger"></span>
</div>
</div>
</section>
</fieldset>
</div>
</div>
<div class="row">
<div class="row" style="margin-top:2.25rem;">
<div class="col-xl-8 col-xxl-constrain">
<h3 class="mt-5 mb-2">Additional Options</h3>
<h3 class="mb-2">Additional Options</h3>
<div class="form-group">
<div class="accordion" id="additional">
<div class="accordion-item">
@ -334,104 +346,61 @@
</div>
</script>
<script>
const posStyleSelector = document.getElementById('DefaultView');
posStyleSelector.addEventListener('change', function(e) {
handleStyleSelected(e.target.value);
});
function handleStyleSelected(style) {
switch (style) {
case '0': // Item list only
case '3': // Print
hideDiscountsSection();
hideButtonPriceTextSection();
showCustomPaymentAmountSection();
hideTipsSection();
const description = document.getElementById('description');
const products = document.getElementById('products');
const tips = document.getElementById('tips');
const discounts = document.getElementById('discounts');
const buttonPriceText = document.getElementById('button-price-text');
const customPayments = document.getElementById('custom-payments');
function hide(el) {
el.setAttribute('hidden', true);
}
function show(el) {
el.removeAttribute('hidden');
}
function updateFormForDefaultView(type) {
console.log(type)
switch (type) {
case 'Static':
case 'Print':
hide(tips);
hide(discounts);
hide(buttonPriceText);
show(description);
show(products);
show(customPayments);
break;
case '1': // Item list and cart
showDiscountsSection();
showButtonPriceTextSection();
showCustomPaymentAmountSection();
showTipsSection();
case 'Cart':
show(tips);
show(products);
show(discounts);
show(description);
show(buttonPriceText);
show(customPayments);
break;
case '2': // Keypad only
showDiscountsSection();
hideButtonPriceTextSection();
hideCustomPaymentAmountSection();
showTipsSection();
case 'Light':
show(tips);
show(discounts);
hide(products);
hide(description);
hide(buttonPriceText);
hide(customPayments);
break;
}
}
/** Show/hide discounts section */
const discountsSection = document.getElementById('discounts');
function hideDiscountsSection() {
hideElement(discountsSection);
}
function showDiscountsSection() {
showElement(discountsSection);
}
/***************************************/
/** Show/hide button text section */
const buttonPriceTextSection = document.getElementById('button-price-text');
function hideButtonPriceTextSection() {
hideElement(buttonPriceTextSection);
}
function showButtonPriceTextSection() {
showElement(buttonPriceTextSection);
}
/***************************************/
/** Show/hide custom payments amount seciton */
const customPaymentAmountSection = document.getElementById('custom-payments');
function hideCustomPaymentAmountSection() {
hideElement(customPaymentAmountSection);
}
function showCustomPaymentAmountSection() {
showElement(customPaymentAmountSection);
}
/***************************************/
/** Show/hide tips seciton */
const tipsSection = document.getElementById('tips');
function hideTipsSection() {
hideElement(tipsSection);
}
function showTipsSection() {
showElement(tipsSection);
}
/***************************************/
function hideElement(el) {
el.setAttribute('hidden', true);
}
function showElement(el) {
el.removeAttribute('hidden');
}
document.addEventListener("DOMContentLoaded", function() {
handleStyleSelected(posStyleSelector.value);
document.addEventListener('DOMContentLoaded', () => {
const defaultView = document.querySelector('input[name="DefaultView"]:checked');
if (defaultView) {
updateFormForDefaultView(defaultView.value);
}
});
delegate('change', 'input[name="DefaultView"]', e => {
updateFormForDefaultView(e.target.value);
});
</script>
<script src="~/vendor/vuejs/vue.min.js" asp-append-version="true"></script>
<script src="~/vendor/summernote/summernote-bs5.js" asp-append-version="true"></script>
}

View file

@ -50,4 +50,8 @@
<symbol id="invoice-expired" viewBox="0 0 48 48" fill="none"><circle cx="24" cy="24" r="22.5" stroke="currentColor" stroke-width="3"/><path d="m17 31 14-14m-14 0 14 14" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></symbol>
<symbol id="payment-sent" viewBox="0 0 48 48" fill="none"><circle cx="24" cy="24" r="22.5" stroke="currentColor" stroke-width="3"/><path d="M24 16v16m5.71-10.29L24 16l-6.29 6.29" stroke="currentColor" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/></symbol>
<symbol id="payment-complete" viewBox="0 0 48 48" fill="none"><path d="M47 24a22.5 22.5 0 1 1-45 0 22.5 22.5 0 0 1 45 0Z" stroke="currentColor" stroke-width="3"/><path d="m15.23 24.8 7.1 7.1 12.8-12.8" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></symbol>
<symbol id="pos-static" viewBox="0 0 24 24"><path d="M19.05 10.266v6.265a2.244 2.244 0 0 1-2.238 2.238H7.246a2.244 2.244 0 0 1-2.238-2.238v-6.265" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10"/><path d="M9.455 5.262v3.833c0 1.174-.951 2.153-2.126 2.153h-.42a2.613 2.613 0 0 1-2.405-3.664l.56-1.315A1.702 1.702 0 0 1 6.63 5.234l2.825.028ZM14.547 5.258V9.09c0 1.175.95 2.154 2.126 2.154h.42c1.901 0 3.16-1.93 2.405-3.665l-.56-1.314a1.721 1.721 0 0 0-1.566-1.007h-2.825ZM12.002 11.499A2.525 2.525 0 0 1 9.484 8.98V5.29h5.063v3.692c0 1.399-1.147 2.518-2.545 2.518Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10"/></symbol>
<symbol id="pos-cart" viewBox="0 0 24 24"><path d="M16.88 19.426H7.12a2.286 2.286 0 0 1-2.286-2.537l.766-6.731A1.143 1.143 0 0 1 6.743 9.14h10.514a1.143 1.143 0 0 1 1.143 1.017l.743 6.731a2.286 2.286 0 0 1-2.263 2.537Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M7.43 9.142a4.571 4.571 0 1 1 9.143 0M9.14 12.57h5.715" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></symbol>
<symbol id="pos-light" viewBox="0 0 24 24"><path d="M8 4h8c2.2 0 4 1.8 4 4v8c0 2.2-1.8 4-4 4H8c-2.2 0-4-1.8-4-4V8c0-2.2 1.8-4 4-4Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10"/><path d="M8 13h8M8 16.25h8" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><rect x="7" y="7" width="10" height="3.5" rx="1" fill="currentColor"/></symbol>
<symbol id="pos-print" viewBox="0 0 24 24"><path d="M5 6v13.543l2.333-.914L9.667 20 12 18.629 14.333 20l2.334-1.371 2.333.914V6a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2Z" stroke="currentColor" stroke-width="1.6"/><path d="M8.5 8h7M8.5 11.5h7M8.5 15h4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></symbol>
</svg>

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View file

@ -588,3 +588,41 @@ svg.icon-note {
}
.modal-footer .modal-footer-left{ margin-right: auto; }
/* List Select */
.btcpay-list-select {
display: flex;
flex-wrap: wrap;
gap: var(--btcpay-space-s);
}
.btcpay-list-select > input {
display: none;
}
.btcpay-list-select-item {
display: flex;
flex: 1 1 45%;
align-items: center;
border: 1px solid var(--btcpay-form-border);
padding: .75rem var(--btcpay-space-s);
background-color: var(--btcpay-form-bg);
border-radius: var(--btcpay-border-radius);
transition: border-color 0.15s ease-in-out;
cursor: pointer;
}
@media (max-width: 575px) {
.btcpay-list-select-item {
flex-basis: 100%;
}
}
.btcpay-list-select-item .icon {
width: 1.5rem;
height: 1.5rem;
margin: 0 var(--btcpay-space-s);
}
.btcpay-list-select-item:hover {
border-color: var(--btcpay-form-border-hover);
background-color: var(--btcpay-form-bg-hover);
}
input:checked + .btcpay-list-select-item {
border-color: var(--btcpay-form-border-focus);
}