Updates Crowdfund & POS Modal (#3806)

* ui+cf: updates perks modal

* Toggle editor with Bootstrap

* Add currency info to app items

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
This commit is contained in:
dstrukt 2022-06-19 19:55:47 -07:00 committed by GitHub
parent cade6c6c38
commit c531b26821
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 107 additions and 88 deletions

View file

@ -25,7 +25,7 @@ namespace BTCPayServer.Controllers
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[HttpGet("{appId}/settings/crowdfund")]
public IActionResult UpdateCrowdfund(string appId)
public async Task<IActionResult> UpdateCrowdfund(string appId)
{
var app = GetCurrentApp();
if (app == null)
@ -37,6 +37,7 @@ namespace BTCPayServer.Controllers
Title = settings.Title,
StoreId = app.StoreDataId,
StoreName = app.StoreData?.StoreName,
StoreDefaultCurrency = await GetStoreDefaultCurrentIfEmpty(app.StoreDataId, settings.TargetCurrency),
AppName = app.Name,
Enabled = settings.Enabled,
EnforceTargetAmount = settings.EnforceTargetAmount,

View file

@ -16,7 +16,7 @@ namespace BTCPayServer.Controllers
public partial class UIAppsController
{
[HttpGet("{appId}/settings/pos")]
public IActionResult UpdatePointOfSale(string appId)
public async Task<IActionResult> UpdatePointOfSale(string appId)
{
var app = GetCurrentApp();
if (app == null)
@ -25,11 +25,13 @@ namespace BTCPayServer.Controllers
var settings = app.GetSettings<PointOfSaleSettings>();
settings.DefaultView = settings.EnableShoppingCart ? PosViewType.Cart : settings.DefaultView;
settings.EnableShoppingCart = false;
var vm = new UpdatePointOfSaleViewModel
{
Id = appId,
StoreId = app.StoreDataId,
StoreName = app.StoreData?.StoreName,
StoreDefaultCurrency = await GetStoreDefaultCurrentIfEmpty(app.StoreDataId, settings.Currency),
AppName = app.Name,
Title = settings.Title,
DefaultView = settings.DefaultView,

View file

@ -10,6 +10,7 @@ namespace BTCPayServer.Models.AppViewModels
{
public string StoreId { get; set; }
public string StoreName { get; set; }
public string StoreDefaultCurrency { get; set; }
[Required]
[MaxLength(50)]

View file

@ -10,6 +10,7 @@ namespace BTCPayServer.Models.AppViewModels
{
public string StoreId { get; set; }
public string StoreName { get; set; }
public string StoreDefaultCurrency { get; set; }
[Required]
[MaxLength(50)]

View file

@ -1,8 +1,8 @@
@model (string templateId, string title)
@model (string templateId, string title, string currency)
<div id="template-editor-app" v-cloak>
<div class="form-group mb-0">
<h3 class="mt-5 mb-4">@Model.title </h3>
<h3 class="mt-5 mb-4">@Model.title</h3>
@if (ViewContext.ViewData.ModelState.TryGetValue(Model.templateId, out var errors))
{
foreach (var error in errors.Errors)
@ -37,7 +37,7 @@
<button type="button" class="btn btn-primary" v-on:click="editItem(-1)" id="btn-add">
<i class="fa fa-plus fa-fw"></i> Add
</button>
<button type="button" class="btn btn-secondary" v-on:click="toggleTemplateElement()" id="ToggleRawEditor">
<button type="button" class="btn btn-secondary" id="ToggleRawEditor" data-bs-toggle="collapse" data-bs-target="#RawEditor" aria-expanded="false" aria-controls="RawEditor">
Toggle raw editor
</button>
</div>
@ -46,7 +46,7 @@
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" v-if="editingItem">{{editingItem.index>=0? "Edit" : "Create"}} item</h5>
<h5 class="modal-title" v-if="editingItem">{{editingItem.index>=0? "Edit" : "Add"}} Item</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" ref="close">
<vc:icon symbol="close"/>
</button>
@ -54,60 +54,69 @@
<div class="modal-body" v-if="editingItem">
<div class="mb-3">
<span class="text-danger row m-2" v-for="error of errors">{{error}}</span>
<div class="form-group">
<label class="form-label" data-required>Title</label>
<input type="text" required pattern="[^\*#]+" class="form-control mb-2" v-model="editingItem.title" autofocus ref="txtTitle" />
</div>
<div class="form-group row">
<div class="col-sm-6">
<label class="form-label" data-required>Title</label>
<input type="text" required pattern="[^\*#]+" class="form-control mb-2" v-model="editingItem.title" autofocus ref="txtTitle"/>
</div>
<div class="col-sm-3 px-0">
<label class="form-label">Price</label>
<select class="form-select" v-model="editingItem.custom">
<option v-for="option in customPriceOptions" :value="option.value">{{option.text}}</option>
</select>
</div>
<div class="col-sm-3" v-show="editingItem.custom !== 'topup'">
<label class="form-label">&nbsp</label>
<input class="form-control mb-2"
inputmode="decimal"
pattern="\d*"
step="any"
min="0"
type="number"
required
v-model="editingItem.price" ref="txtPrice"/>
<div class="col-sm-6" v-show="editingItem.custom !== 'topup'">
<label class="form-label">&nbsp;</label>
<div class="input-group mb-2">
<input class="form-control"
inputmode="decimal"
pattern="\d*"
step="any"
min="0"
type="number"
required
v-model="editingItem.price"
ref="txtPrice"
aria-describedby="currency-addon"/>
<span class="input-group-text" id="currency-addon">@Model.currency</span>
</div>
</div>
</div>
<div class="form-group">
<label class="form-label">Image</label>
<input type="text" class="form-control mb-2" pattern="[^\*#]+" v-model="editingItem.image" ref="txtImage"/>
<label class="form-label">Image Url</label>
<input type="text" class="form-control mb-2" pattern="[^\*#]+" v-model="editingItem.image" ref="txtImage" />
</div>
<div class="form-group">
<label class="form-label">Description</label>
<textarea rows="3" cols="40" class="form-control mb-2" v-model="editingItem.description" ref="txtDescription"></textarea>
</div>
<div class="form-group">
<label class="form-label">Inventory (leave blank to not use inventory feature)</label>
<input type="number" inputmode="numeric" min="0" step="1" class="form-control mb-2" v-model="editingItem.inventory" ref="txtInventory"/>
<label class="form-label">Inventory</label>
<input type="number" inputmode="numeric" min="0" step="1" class="form-control mb-2" v-model="editingItem.inventory" ref="txtInventory" />
<p class="form-text text-muted">
Leave blank to not use this feature.
</p>
</div>
<div class="form-group">
<label class="form-label">Id (leave blank to generate from title)</label>
<input type="text" required pattern="[^\*#]+" class="form-control mb-2" v-model="editingItem.id" ref="txtId"/>
<label class="form-label">ID</label>
<input type="text" required pattern="[^\*#]+" class="form-control mb-2" v-model="editingItem.id" ref="txtId" />
<p class="form-text text-muted">
Leave blank to generate ID from title.
</p>
</div>
<div class="form-group">
<label class="form-label">Buy Button Text</label>
<input type="text" id="BuyButtonText" class="form-control mb-2" v-model="editingItem.buyButtonText" ref="txtBuyButtonText"/>
<input type="text" id="BuyButtonText" class="form-control mb-2" v-model="editingItem.buyButtonText" ref="txtBuyButtonText" />
</div>
<div class="form-group d-flex align-items-center">
<input type="checkbox" id="Disabled" class="btcpay-toggle me-2" v-model="editingItem.disabled"/>
<input type="checkbox" id="Disabled" class="btcpay-toggle me-3" v-model="editingItem.disabled" />
<label class="form-label mb-0">Disabled</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" v-on:click="clearEditingItem()">Close</button>
<button type="button" class="btn btn-primary" v-on:click="saveEditingItem()" id="SaveItemChanges">Save Changes</button>
<button type="button" class="btn btn-primary" v-on:click="saveEditingItem()" id="SaveItemChanges">Save</button>
</div>
</div>
</div>
@ -139,12 +148,8 @@ document.addEventListener("DOMContentLoaded", function () {
this.loadYml();
this.getInputElement().on("input change", this.loadYml.bind(this));
this.getModalElement().on("hide.bs.modal", this.clearEditingItem.bind(this));
this.toggleTemplateElement();
},
methods: {
toggleTemplateElement: function(){
this.getInputElement().parent().toggle();
},
getImage: function(item){
var image = this.unEscapeKey(item.image) || "~/img/img-placeholder.svg";
var url = image.startsWith("~") ? image.replace('~', window.location.pathname.substring(0, image.indexOf('/apps'))) : image;

View file

@ -85,70 +85,74 @@
</div>
<div class="form-group">
<label asp-for="TargetCurrency" class="form-label"></label>
<input asp-for="TargetCurrency" class="form-control" placeholder="Use store's default settings" />
<input asp-for="TargetCurrency" class="form-control" currency-selection style="max-width:10ch;" />
<small class="d-inline-block form-text text-muted">Uses the store's default currency (@Model.StoreDefaultCurrency) if empty.</small>
<span asp-validation-for="TargetCurrency" class="text-danger"></span>
</div>
</div>
<div class="row g-3">
<div class="col col-12 col-sm-6">
<div class="form-group">
<label asp-for="StartDate" class="form-label"></label>
<div class="input-group flex-nowrap">
<input type="datetime-local" asp-for="StartDate"
value="@(Model.StartDate?.ToString("u", CultureInfo.InvariantCulture))"
class="form-control flatdtpicker"
placeholder="No start date has been set" />
<button class="btn btn-secondary input-group-clear" type="button" title="Clear">
<span class="fa fa-times"></span>
</button>
</div>
<span asp-validation-for="StartDate" class="text-danger"></span>
</div>
</div>
<div class="col col-12 col-sm-6">
<div class="form-group">
<label asp-for="EndDate" class="form-label"></label>
<div class="input-group flex-nowrap">
<input type="datetime-local" asp-for="EndDate"
value="@(Model.EndDate?.ToString("u", CultureInfo.InvariantCulture))"
class="form-control flatdtpicker"
placeholder="No end date has been set" />
<button class="btn btn-secondary input-group-clear input-group-text" type="button" title="Clear">
<span class="fa fa-times"></span>
</button>
</div>
<span asp-validation-for="EndDate" class="text-danger"></span>
<div class="row g-3">
<div class="col col-12 col-sm-6">
<div class="form-group">
<label asp-for="StartDate" class="form-label"></label>
<div class="input-group flex-nowrap">
<input type="datetime-local" asp-for="StartDate"
value="@(Model.StartDate?.ToString("u", CultureInfo.InvariantCulture))"
class="form-control flatdtpicker"
placeholder="No start date has been set" />
<button class="btn btn-secondary input-group-clear" type="button" title="Clear">
<span class="fa fa-times"></span>
</button>
</div>
<span asp-validation-for="StartDate" class="text-danger"></span>
</div>
</div>
<div class="form-group mb-0" id="ResetRow" hidden="@(Model.StartDate == null)">
<label asp-for="ResetEvery" class="form-label"></label>
<div class="input-group">
<input type="number" inputmode="numeric" asp-for="ResetEveryAmount" placeholder="Amount" class="form-control" min="0">
<select class="form-select" asp-for="ResetEvery">
@foreach (var opt in Model.ResetEveryValues)
{
<option value="@opt">@opt</option>
}
</select>
<div class="col col-12 col-sm-6">
<div class="form-group">
<label asp-for="EndDate" class="form-label"></label>
<div class="input-group flex-nowrap">
<input type="datetime-local" asp-for="EndDate"
value="@(Model.EndDate?.ToString("u", CultureInfo.InvariantCulture))"
class="form-control flatdtpicker"
placeholder="No end date has been set" />
<button class="btn btn-secondary input-group-clear input-group-text" type="button" title="Clear">
<span class="fa fa-times"></span>
</button>
</div>
<span asp-validation-for="EndDate" class="text-danger"></span>
</div>
<span asp-validation-for="ResetEveryAmount" class="text-danger"></span>
</div>
</div>
<div class="form-group mb-0" id="ResetRow" hidden="@(Model.StartDate == null)">
<label asp-for="ResetEvery" class="form-label"></label>
<div class="input-group">
<input type="number" inputmode="numeric" asp-for="ResetEveryAmount" placeholder="Amount" class="form-control" min="0">
<select class="form-select" asp-for="ResetEvery">
@foreach (var opt in Model.ResetEveryValues)
{
<option value="@opt">@opt</option>
}
</select>
</div>
<span asp-validation-for="ResetEveryAmount" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-xxl-constrain">
<partial name="TemplateEditor" model="@(nameof(Model.PerksTemplate), "Perks")" />
<div class="col-xl-10 col-xxl-constrain">
<partial name="TemplateEditor" model="@(nameof(Model.PerksTemplate), "Perks", Model.TargetCurrency ?? Model.StoreDefaultCurrency)" />
</div>
</div>
<div class="row collapse" id="RawEditor">
<div class="col-xl-10 col-xxl-constrain">
<div class="form-group pt-3">
<label asp-for="PerksTemplate" class="form-label"></label>
<textarea asp-for="PerksTemplate" rows="10" cols="40" class="form-control"></textarea>
<span asp-validation-for="PerksTemplate" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div class="form-group">
<label asp-for="PerksTemplate" class="form-label"></label>
<textarea asp-for="PerksTemplate" rows="10" cols="40" class="js-product-template form-control"></textarea>
<span asp-validation-for="PerksTemplate" class="text-danger"></span>
</div>
<h3 class="mt-5 mb-4">Contributions</h3>
<div class="form-check mb-3">
<input asp-for="SortPerksByPopularity" type="checkbox" class="form-check-input" />

View file

@ -34,7 +34,8 @@
</div>
<div class="form-group">
<label asp-for="Currency" class="form-label"></label>
<input asp-for="Currency" currency-selection class="form-control" placeholder="Use store's default settings" />
<input asp-for="Currency" class="form-control" currency-selection style="max-width:10ch;" />
<small class="d-inline-block form-text text-muted">Uses the store's default currency (@Model.StoreDefaultCurrency) if empty.</small>
<span asp-validation-for="Currency" class="text-danger"></span>
</div>
</div>
@ -50,10 +51,14 @@
</div>
<div class="row">
<div class="col-xxl-constrain">
<partial name="TemplateEditor" model="@(nameof(Model.Template), "Products")" />
<div class="form-group mb-0">
<partial name="TemplateEditor" model="@(nameof(Model.Template), "Products", Model.Currency ?? Model.StoreDefaultCurrency)" />
</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="js-product-template form-control"></textarea>
<textarea asp-for="Template" rows="10" cols="40" class="form-control"></textarea>
<span asp-validation-for="Template" class="text-danger"></span>
</div>
</div>