From ed43fb20710aaebeaede07e9a15cb71ed727c7b3 Mon Sep 17 00:00:00 2001 From: d11n Date: Wed, 9 Aug 2023 15:47:28 +0300 Subject: [PATCH] POS fixes (#5241) --- BTCPayServer.Abstractions/Services/Safe.cs | 1 + BTCPayServer.Tests/SeleniumTests.cs | 6 ++-- .../Shared/PointOfSale/Public/Cart.cshtml | 8 ++--- BTCPayServer/wwwroot/pos/cart.css | 10 ++++++ BTCPayServer/wwwroot/pos/cart.js | 35 +++++++++++++------ 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/BTCPayServer.Abstractions/Services/Safe.cs b/BTCPayServer.Abstractions/Services/Safe.cs index cb8a22d82..88d0d2c50 100644 --- a/BTCPayServer.Abstractions/Services/Safe.cs +++ b/BTCPayServer.Abstractions/Services/Safe.cs @@ -22,6 +22,7 @@ namespace BTCPayServer.Abstractions.Services { return _htmlHelper.Raw(_htmlSanitizer.Sanitize(value)); } + public IHtmlContent RawEncode(string value) { return _htmlHelper.Raw(HttpUtility.HtmlEncode(_htmlSanitizer.Sanitize(value))); diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index 1d16dca03..b5a29351d 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -988,14 +988,14 @@ namespace BTCPayServer.Tests Assert.True(s.Driver.PageSource.Contains("Tea shop"), "Unable to create PoS"); Assert.True(s.Driver.PageSource.Contains("Cart"), "PoS not showing correct default view"); Assert.True(s.Driver.PageSource.Contains("Take my money"), "PoS not showing correct default view"); - Assert.Equal(6, s.Driver.FindElements(By.CssSelector(".posItem:not(.d-none)")).Count); + Assert.Equal(6, s.Driver.FindElements(By.CssSelector(".posItem.posItem--displayed")).Count); var drinks = s.Driver.FindElement(By.CssSelector("label[for='Category-Drinks']")); Assert.Equal("Drinks", drinks.Text); drinks.Click(); - Assert.Single(s.Driver.FindElements(By.CssSelector(".posItem:not(.d-none)"))); + Assert.Single(s.Driver.FindElements(By.CssSelector(".posItem.posItem--displayed"))); s.Driver.FindElement(By.CssSelector("label[for='Category-*']")).Click(); - Assert.Equal(6, s.Driver.FindElements(By.CssSelector(".posItem:not(.d-none)")).Count); + Assert.Equal(6, s.Driver.FindElements(By.CssSelector(".posItem.posItem--displayed")).Count); s.Driver.Url = posBaseUrl + "/static"; Assert.False(s.Driver.PageSource.Contains("Cart"), "Static PoS not showing correct view"); diff --git a/BTCPayServer/Views/Shared/PointOfSale/Public/Cart.cshtml b/BTCPayServer/Views/Shared/PointOfSale/Public/Cart.cshtml index 68e3294c2..0d081734d 100644 --- a/BTCPayServer/Views/Shared/PointOfSale/Public/Cart.cshtml +++ b/BTCPayServer/Views/Shared/PointOfSale/Public/Cart.cshtml @@ -64,14 +64,14 @@ : item.BuyButtonText; buttonText = buttonText.Replace("{0}", formatted).Replace("{Price}", formatted); var categories = new JArray(item.Categories ?? new object[] { }); -
+
@if (!string.IsNullOrWhiteSpace(item.Image)) { @item.Title }
-
@Safe.RawEncode(item.Title)
+
@Safe.Raw(item.Title)
@if (item.PriceType == ViewPointOfSaleViewModel.ItemPriceType.Topup || item.Price == 0) { @@ -90,7 +90,7 @@
@if (!string.IsNullOrWhiteSpace(item.Description)) { -

@Safe.RawEncode(item.Description)

+

@Safe.Raw(item.Description)

}
@if (inStock) @@ -104,7 +104,7 @@
}
diff --git a/BTCPayServer/wwwroot/pos/cart.css b/BTCPayServer/wwwroot/pos/cart.css index 9b7585024..2e385b884 100644 --- a/BTCPayServer/wwwroot/pos/cart.css +++ b/BTCPayServer/wwwroot/pos/cart.css @@ -87,6 +87,7 @@ header .cart-toggle-btn { } .posItem { + display: none; position: relative; } .posItem.posItem--inStock { @@ -117,6 +118,15 @@ header .cart-toggle-btn { .posItem--added .posItem-added { opacity: .8; } +.posItem--displayed { + display: flex; +} +.posItem--first { + margin-left: auto; +} +.posItem--last { + margin-right: auto; +} @media (max-width: 991px) { #cart { diff --git a/BTCPayServer/wwwroot/pos/cart.js b/BTCPayServer/wwwroot/pos/cart.js index aecd020b7..d93db5220 100644 --- a/BTCPayServer/wwwroot/pos/cart.js +++ b/BTCPayServer/wwwroot/pos/cart.js @@ -68,19 +68,10 @@ document.addEventListener("DOMContentLoaded",function () { }, watch: { searchTerm(term) { - const t = term.toLowerCase(); - this.forEachItem(item => { - const terms = decodeURIComponent(item.dataset.search.toLowerCase()); - const included = terms.indexOf(t) !== -1 - item.classList[included ? 'remove' : 'add']("d-none") - }) + this.updateDisplay() }, displayCategory(category) { - this.forEachItem(item => { - const categories = JSON.parse(item.dataset.categories) - const included = category === "*" || categories.includes(category) - item.classList[included ? 'remove' : 'add']("d-none") - }) + this.updateDisplay() }, cart: { handler(newCart) { @@ -166,6 +157,27 @@ document.addEventListener("DOMContentLoaded",function () { }, clearCart() { this.cart = []; + }, + displayItem(item) { + const inSearch = !this.searchTerm || + decodeURIComponent(item.dataset.search ? item.dataset.search.toLowerCase() : '') + .indexOf(this.searchTerm.toLowerCase()) !== -1 + const inCategories = this.displayCategory === "*" || + (item.dataset.categories ? JSON.parse(item.dataset.categories) : []) + .includes(this.displayCategory) + return inSearch && inCategories + }, + updateDisplay() { + this.forEachItem(item => { + item.classList[this.displayItem(item) ? 'add' : 'remove']('posItem--displayed') + item.classList.remove('posItem--first') + item.classList.remove('posItem--last') + }) + const $displayed = this.$refs.posItems.querySelectorAll('.posItem.posItem--displayed') + if ($displayed.length > 0) { + $displayed[0].classList.add('posItem--first') + $displayed[$displayed.length - 1].classList.add('posItem--last') + } } }, mounted() { @@ -184,6 +196,7 @@ document.addEventListener("DOMContentLoaded",function () { } }); }) + this.updateDisplay() }, }); });