diff --git a/BTCPayServer/Controllers/StoresController.cs b/BTCPayServer/Controllers/StoresController.cs index 3b65ca215..d11045b29 100644 --- a/BTCPayServer/Controllers/StoresController.cs +++ b/BTCPayServer/Controllers/StoresController.cs @@ -183,6 +183,65 @@ namespace BTCPayServer.Controllers return RedirectToAction(nameof(StoreUsers), new { storeId = storeId, userId = userId }); } + [HttpGet] + [Route("{storeId}/checkout")] + public async Task CheckoutExperience(string storeId) + { + var store = await _Repo.FindStore(storeId, GetUserId()); + if (store == null) + return NotFound(); + var storeBlob = store.GetStoreBlob(); + var vm = new CheckoutExperienceViewModel(); + vm.SetCryptoCurrencies(_ExplorerProvider, store.GetDefaultCrypto()); + vm.SetLanguages(_LangService, storeBlob.DefaultLang); + vm.LightningMaxValue = storeBlob.LightningMaxValue?.ToString() ?? ""; + vm.AllowCoinConversion = storeBlob.AllowCoinConversion; + return View(vm); + } + + [HttpPost] + [Route("{storeId}/checkout")] + public async Task CheckoutExperience(string storeId, CheckoutExperienceViewModel model) + { + CurrencyValue currencyValue = null; + if (!string.IsNullOrWhiteSpace(model.LightningMaxValue)) + { + if (!CurrencyValue.TryParse(model.LightningMaxValue, out currencyValue)) + { + ModelState.AddModelError(nameof(model.LightningMaxValue), "Invalid currency value"); + } + } + var store = await _Repo.FindStore(storeId, GetUserId()); + if (store == null) + return NotFound(); + bool needUpdate = false; + var blob = store.GetStoreBlob(); + if (store.GetDefaultCrypto() != model.DefaultCryptoCurrency) + { + needUpdate = true; + store.SetDefaultCrypto(model.DefaultCryptoCurrency); + } + model.SetCryptoCurrencies(_ExplorerProvider, model.DefaultCryptoCurrency); + model.SetLanguages(_LangService, model.DefaultLang); + blob.DefaultLang = model.DefaultLang; + blob.AllowCoinConversion = model.AllowCoinConversion; + blob.LightningMaxValue = currencyValue; + if (store.SetStoreBlob(blob)) + { + needUpdate = true; + } + if (needUpdate) + { + await _Repo.UpdateStore(store); + StatusMessage = "Store successfully updated"; + } + + return RedirectToAction(nameof(CheckoutExperience), new + { + storeId = storeId + }); + } + [HttpGet] [Route("{storeId}")] public async Task UpdateStore(string storeId) @@ -195,19 +254,14 @@ namespace BTCPayServer.Controllers var vm = new StoreViewModel(); vm.Id = store.Id; vm.StoreName = store.StoreName; - vm.SetCryptoCurrencies(_ExplorerProvider, store.GetDefaultCrypto()); - vm.SetLanguages(_LangService, storeBlob.DefaultLang); vm.StoreWebsite = store.StoreWebsite; vm.NetworkFee = !storeBlob.NetworkFeeDisabled; - vm.LightningMaxValue = storeBlob.LightningMaxValue?.ToString() ?? ""; vm.SpeedPolicy = store.SpeedPolicy; AddPaymentMethods(store, vm); - vm.StatusMessage = StatusMessage; vm.MonitoringExpiration = storeBlob.MonitoringExpiration; vm.InvoiceExpiration = storeBlob.InvoiceExpiration; vm.RateMultiplier = (double)storeBlob.GetRateMultiplier(); vm.PreferredExchange = storeBlob.PreferredExchange.IsCoinAverage() ? "coinaverage" : storeBlob.PreferredExchange; - vm.AllowCoinConversion = storeBlob.AllowCoinConversion; return View(vm); } @@ -249,14 +303,6 @@ namespace BTCPayServer.Controllers [Route("{storeId}")] public async Task UpdateStore(string storeId, StoreViewModel model) { - CurrencyValue currencyValue = null; - if (!string.IsNullOrWhiteSpace(model.LightningMaxValue)) - { - if(!CurrencyValue.TryParse(model.LightningMaxValue, out currencyValue)) - { - ModelState.AddModelError(nameof(model.LightningMaxValue), "Invalid currency value"); - } - } if (!ModelState.IsValid) { return View(model); @@ -285,26 +331,15 @@ namespace BTCPayServer.Controllers store.StoreWebsite = model.StoreWebsite; } - if (store.GetDefaultCrypto() != model.DefaultCryptoCurrency) - { - needUpdate = true; - store.SetDefaultCrypto(model.DefaultCryptoCurrency); - } - model.SetCryptoCurrencies(_ExplorerProvider, model.DefaultCryptoCurrency); - model.SetLanguages(_LangService, model.DefaultLang); - var blob = store.GetStoreBlob(); blob.NetworkFeeDisabled = !model.NetworkFee; blob.MonitoringExpiration = model.MonitoringExpiration; blob.InvoiceExpiration = model.InvoiceExpiration; - blob.DefaultLang = model.DefaultLang; - blob.LightningMaxValue = currencyValue; bool newExchange = blob.PreferredExchange != model.PreferredExchange; blob.PreferredExchange = model.PreferredExchange; blob.SetRateMultiplier(model.RateMultiplier); - blob.AllowCoinConversion = model.AllowCoinConversion; if (store.SetStoreBlob(blob)) { diff --git a/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs b/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs new file mode 100644 index 000000000..55f4dc05a --- /dev/null +++ b/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using BTCPayServer.Services; +using Microsoft.AspNetCore.Mvc.Rendering; + +namespace BTCPayServer.Models.StoreViewModels +{ + public class CheckoutExperienceViewModel + { + class Format + { + public string Name { get; set; } + public string Value { get; set; } + } + public SelectList CryptoCurrencies { get; set; } + public SelectList Languages { get; set; } + + [Display(Name = "Default crypto currency on checkout")] + public string DefaultCryptoCurrency { get; set; } + [Display(Name = "Default language on checkout")] + public string DefaultLang { get; set; } + [Display(Name = "Allow conversion through third party (Shapeshift, Changelly...)")] + public bool AllowCoinConversion + { + get; set; + } + [Display(Name = "Do not propose lightning payment if value of the invoice is above...")] + [MaxLength(20)] + public string LightningMaxValue { get; set; } + public void SetCryptoCurrencies(ExplorerClientProvider explorerProvider, string defaultCrypto) + { + var choices = explorerProvider.GetAll().Select(o => new Format() { Name = o.Item1.CryptoCode, Value = o.Item1.CryptoCode }).ToArray(); + var chosen = choices.FirstOrDefault(f => f.Value == defaultCrypto) ?? choices.FirstOrDefault(); + CryptoCurrencies = new SelectList(choices, nameof(chosen.Value), nameof(chosen.Name), chosen); + DefaultCryptoCurrency = chosen.Name; + } + + public void SetLanguages(LanguageService langService, string defaultLang) + { + defaultLang = defaultLang ?? "en-US"; + var choices = langService.GetLanguages().Select(o => new Format() { Name = o.DisplayName, Value = o.Code }).ToArray(); + var chosen = choices.FirstOrDefault(f => f.Value == defaultLang) ?? choices.FirstOrDefault(); + Languages = new SelectList(choices, nameof(chosen.Value), nameof(chosen.Name), chosen); + DefaultLang = chosen.Value; + } + } +} diff --git a/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs b/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs index ed4bc7382..1e95bc7d9 100644 --- a/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs @@ -17,11 +17,7 @@ namespace BTCPayServer.Models.StoreViewModels public string Crypto { get; set; } public string Value { get; set; } } - class Format - { - public string Name { get; set; } - public string Value { get; set; } - } + public StoreViewModel() { @@ -83,11 +79,6 @@ namespace BTCPayServer.Models.StoreViewModels set; } - - [Display(Name = "Do not propose lightning payment if value of the invoice is above...")] - [MaxLength(20)] - public string LightningMaxValue { get; set; } - [Display(Name = "Consider the invoice confirmed when the payment transaction...")] public SpeedPolicy SpeedPolicy { @@ -100,24 +91,6 @@ namespace BTCPayServer.Models.StoreViewModels get; set; } - [Display(Name = "Allow conversion through third party (Shapeshift, Changelly...)")] - public bool AllowCoinConversion - { - get; set; - } - - public string StatusMessage - { - get; set; - } - public SelectList CryptoCurrencies { get; set; } - public SelectList Languages { get; set; } - - [Display(Name = "Default crypto currency on checkout")] - public string DefaultCryptoCurrency { get; set; } - [Display(Name = "Default language on checkout")] - public string DefaultLang { get; set; } - public class LightningNode { public string CryptoCode { get; set; } @@ -128,21 +101,5 @@ namespace BTCPayServer.Models.StoreViewModels get; set; } = new List(); - public void SetCryptoCurrencies(ExplorerClientProvider explorerProvider, string defaultCrypto) - { - var choices = explorerProvider.GetAll().Select(o => new Format() { Name = o.Item1.CryptoCode, Value = o.Item1.CryptoCode }).ToArray(); - var chosen = choices.FirstOrDefault(f => f.Value == defaultCrypto) ?? choices.FirstOrDefault(); - CryptoCurrencies = new SelectList(choices, nameof(chosen.Value), nameof(chosen.Name), chosen); - DefaultCryptoCurrency = chosen.Name; - } - - public void SetLanguages(LanguageService langService, string defaultLang) - { - defaultLang = defaultLang ?? "en-US"; - var choices = langService.GetLanguages().Select(o => new Format() { Name = o.DisplayName, Value = o.Code }).ToArray(); - var chosen = choices.FirstOrDefault(f => f.Value == defaultLang) ?? choices.FirstOrDefault(); - Languages = new SelectList(choices, nameof(chosen.Value), nameof(chosen.Name), chosen); - DefaultLang = chosen.Value; - } } } diff --git a/BTCPayServer/Views/Stores/CheckoutExperience.cshtml b/BTCPayServer/Views/Stores/CheckoutExperience.cshtml new file mode 100644 index 000000000..72a68b91c --- /dev/null +++ b/BTCPayServer/Views/Stores/CheckoutExperience.cshtml @@ -0,0 +1,44 @@ +@model CheckoutExperienceViewModel +@{ + Layout = "../Shared/_NavLayout.cshtml"; + ViewData["Title"] = "Checkout experience"; + ViewData.AddActivePage(BTCPayServer.Views.Stores.StoreNavPages.Checkout); +} + +

@ViewData["Title"]

+@Html.Partial("_StatusMessage", TempData["TempDataProperty-StatusMessage"]) + +
+
+
+
+
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + + +

Example: 5.50 USD

+
+ +
+
+
+ +@section Scripts { + @await Html.PartialAsync("_ValidationScriptsPartial") +} diff --git a/BTCPayServer/Views/Stores/StoreNavPages.cs b/BTCPayServer/Views/Stores/StoreNavPages.cs index edb101af3..87c3cb516 100644 --- a/BTCPayServer/Views/Stores/StoreNavPages.cs +++ b/BTCPayServer/Views/Stores/StoreNavPages.cs @@ -11,13 +11,14 @@ namespace BTCPayServer.Views.Stores { public static string ActivePageKey => "ActivePage"; public static string Index => "Index"; - + public static string Checkout => "Checkout experience"; public static string Tokens => "Tokens"; public static string Users => "Users"; public static string UsersNavClass(ViewContext viewContext) => PageNavClass(viewContext, Users); public static string TokensNavClass(ViewContext viewContext) => PageNavClass(viewContext, Tokens); + public static string CheckoutNavClass(ViewContext viewContext) => PageNavClass(viewContext, Checkout); public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index); public static string PageNavClass(ViewContext viewContext, string page) diff --git a/BTCPayServer/Views/Stores/UpdateStore.cshtml b/BTCPayServer/Views/Stores/UpdateStore.cshtml index 9c9c9d3fb..2a18fa082 100644 --- a/BTCPayServer/Views/Stores/UpdateStore.cshtml +++ b/BTCPayServer/Views/Stores/UpdateStore.cshtml @@ -6,7 +6,7 @@ }

@ViewData["Title"]

-@Html.Partial("_StatusMessage", Model.StatusMessage) +@Html.Partial("_StatusMessage", TempData["TempDataProperty-StatusMessage"])
@@ -30,14 +30,6 @@
-
- - -
-
- - -
@@ -74,10 +66,6 @@
-
- - -
Derivation Scheme
The DerivationScheme represents the destination of the funds received by your invoice on chain. @@ -94,19 +82,19 @@ @foreach(var scheme in Model.DerivationSchemes) - { - - @scheme.Crypto - @scheme.Value - - @if(!string.IsNullOrWhiteSpace(scheme.Value)) - { - Wallet - - } - Modify - - - } + { + + @scheme.Crypto + @scheme.Value + + @if(!string.IsNullOrWhiteSpace(scheme.Value)) + { + Wallet - + } + Modify + + + }
@@ -119,12 +107,6 @@ This is experimental and not advised for production.

-
- - - -

Example: 5.50 USD

-
@@ -136,13 +118,13 @@ @foreach(var scheme in Model.LightningNodes) - { - - - - - - } + { + + + + + + }
@scheme.CryptoCode@scheme.AddressModify
@scheme.CryptoCode@scheme.AddressModify
diff --git a/BTCPayServer/Views/Stores/_Nav.cshtml b/BTCPayServer/Views/Stores/_Nav.cshtml index d4552b988..552c4f099 100644 --- a/BTCPayServer/Views/Stores/_Nav.cshtml +++ b/BTCPayServer/Views/Stores/_Nav.cshtml @@ -2,7 +2,8 @@ @inject SignInManager SignInManager