Merge pull request #736 from Dolu89/master

New Pay Button type (Custom amount and Slider)
This commit is contained in:
Nicolas Dorier
2019-04-08 22:19:05 +09:00
committed by GitHub
4 changed files with 140 additions and 18 deletions

View File

@@ -507,7 +507,7 @@ namespace BTCPayServer.Controllers
Action = nameof(UpdateChangellySettings),
Provider = "Changelly"
});
var coinSwitchEnabled = storeBlob.CoinSwitchSettings != null && storeBlob.CoinSwitchSettings.Enabled;
vm.ThirdPartyPaymentMethods.Add(new StoreViewModel.ThirdPartyPaymentMethod()
{
@@ -891,7 +891,11 @@ namespace BTCPayServer.Controllers
ButtonSize = 2,
UrlRoot = appUrl,
PayButtonImageUrl = appUrl + "img/paybutton/pay.png",
StoreId = store.Id
StoreId = store.Id,
ButtonType = 0,
Min = 1,
Max = 20,
Step = 1
};
return View(model);
}

View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.ModelBinders;
using Microsoft.AspNetCore.Mvc;
@@ -18,6 +15,13 @@ namespace BTCPayServer.Models.StoreViewModels
public string CheckoutDesc { get; set; }
public string OrderId { get; set; }
public int ButtonSize { get; set; }
public int ButtonType { get; set; }
// Slider properties (ButtonType = 2)
public decimal Min { get; set; }
public decimal Max { get; set; }
public decimal Step { get; set; }
[Url]
public string ServerIpn { get; set; }
[Url]

View File

@@ -18,7 +18,7 @@
</div>
<div class="form-group col-md-4">
<label>&nbsp;</label>
<input name="price" type="text" class="form-control"
<input name="currency" type="text" class="form-control"
v-model="srvModel.currency" v-on:change="inputChanges"
:class="{'is-invalid': errors.has('currency') }">
</div>
@@ -57,6 +57,44 @@
</button>
</div>
</div>
<div class="form-group">
<label>Button Type</label>
<div>
<input type="radio" name="button-type" id="btn-fixed" value="0" v-model="srvModel.buttonType" v-on:change="inputChanges" checked />
<label for="btn-fixed">Fixed amount</label>
</div>
<div>
<input type="radio" name="button-type" id="btn-custom" value="1" v-model="srvModel.buttonType" v-on:change="inputChanges" />
<label for="btn-custom">Custom amount</label>
</div>
<div>
<input type="radio" name="button-type" id="btn-slider" value="2" v-model="srvModel.buttonType" v-on:change="inputChanges" />
<label for="btn-slider">Slider</label>
</div>
</div>
<div class="form-row" v-if="srvModel.buttonType == 2">
<div class="form-group col-md-4">
<label>Min</label>
<input name="min" type="text" class="form-control"
v-model="srvModel.min" v-on:change="inputChanges"
v-validate="'required|decimal|min_value:1'" :class="{'is-invalid': errors.has('min') }">
<small class="text-danger">{{ errors.first('min') }}</small>
</div>
<div class="form-group col-md-4">
<label>Max</label>
<input name="max" type="text" class="form-control"
v-model="srvModel.max" v-on:change="inputChanges"
v-validate="'required|decimal|min_value:1'" :class="{'is-invalid': errors.has('max') }">
<small class="text-danger">{{ errors.first('max') }}</small>
</div>
<div class="form-group col-md-4">
<label>Step</label>
<input name="step" type="text" class="form-control"
v-model="srvModel.step" v-on:change="inputChanges"
v-validate="'required|decimal|min_value:1'" :class="{'is-invalid': errors.has('step') }">
<small class="text-danger">{{ errors.first('step') }}</small>
</div>
</div>
</div>
<div class="col-lg-5">
<br />
@@ -121,7 +159,7 @@
Please fix errors shown in order for code generation to successfully execute.
</div>
</div>
</div>
@section HeadScripts {
<link rel="stylesheet" href="~/vendor/highlightjs/default.min.css">
@@ -152,3 +190,20 @@
});
</script>
}
<script id="template-select-currency" type="text/template">
<select onchange="document.querySelector('input[type = hidden][name = currency]').value = event.target.value" style="-webkit-appearance: none; border: 0; display: block; padding: 0 3em; margin: auto auto 5px auto; font-size: 11px; background: 0 0; cursor: pointer;"><option value="USD">USD</option><option value="GBP">GBP</option><option value="EUR">EUR</option><option value="BTC">BTC</option></select>
</script>
<script id="template-button-plus-minus" type="text/template">
<button style="cursor:pointer; font-size:25px; line-height: 25px; background: rgba(0,0,0,.1); height: 30px; width: 45px; border:none; border-radius: 60px; margin: auto;" onclick="event.preventDefault(); var price = parseInt(document.querySelector('#btcpay-input-price').value); if ('TYPE' == '-' && (price - 1) < 1) { return; } document.querySelector('#btcpay-input-price').value = parseInt(document.querySelector('#btcpay-input-price').value) TYPE 1;">TYPE</button>
</script>
<script id="template-input-price" type="text/template">
<input type="text" id="btcpay-input-price" name="price" value="PRICEVALUE" style="border: none; background-image: none; background-color: transparent; -webkit-box-shadow: none ; -moz-box-shadow: none ; -webkit-appearance: none ; width: WIDTHINPUT; text-align: center; font-size: 25px; margin: auto; border-radius: 5px; line-height: 35px; background: #fff;" oninput="event.preventDefault();isNaN(event.target.value) || event.target.value <= 0 ? document.querySelector('#btcpay-input-price').value = PRICEVALUE : event.target.value" CUSTOM />
</script>
<script id="template-input-slider" type="text/template">
<input class="btcpay-input-range" id="btcpay-input-range" value="PRICE" type="range" min="MIN" max="MAX" step="STEP" style="width:WIDTH ;margin-bottom:15px;" oninput="document.querySelector('#btcpay-input-price').value = document.querySelector('#btcpay-input-range').value" />
<style type="text/css">input[type=range].btcpay-input-range{-webkit-appearance:none;width:100%;margin:9.45px 0}input[type=range].btcpay-input-range:focus{outline:0}input[type=range].btcpay-input-range::-webkit-slider-runnable-track{width:100%;height:3.1px;cursor:pointer;box-shadow:0 0 1.7px #020,0 0 0 #003c00;background:#f3f3f3;border-radius:1px;border:0 solid rgba(24,213,1,0)}input[type=range].btcpay-input-range::-webkit-slider-thumb{box-shadow:0 0 3.7px rgba(0,170,0,0),0 0 0 rgba(0,195,0,0);border:2.5px solid #cedc21;height:22px;width:23px;border-radius:12px;background:#0f3723;cursor:pointer;-webkit-appearance:none;margin-top:-9.45px}input[type=range].btcpay-input-range:focus::-webkit-slider-runnable-track{background:#fff}input[type=range].btcpay-input-range::-moz-range-track{width:100%;height:3.1px;cursor:pointer;box-shadow:0 0 1.7px #020,0 0 0 #003c00;background:#f3f3f3;border-radius:1px;border:0 solid rgba(24,213,1,0)}input[type=range].btcpay-input-range::-moz-range-thumb{box-shadow:0 0 3.7px rgba(0,170,0,0),0 0 0 rgba(0,195,0,0);border:2.5px solid #cedc21;height:22px;width:23px;border-radius:12px;background:#0f3723;cursor:pointer}input[type=range].btcpay-input-range::-ms-track{width:100%;height:3.1px;cursor:pointer;background:0 0;border-color:transparent;color:transparent}input[type=range].btcpay-input-range::-ms-fill-lower{background:#e6e6e6;border:0 solid rgba(24,213,1,0);border-radius:2px;box-shadow:0 0 1.7px #020,0 0 0 #003c00}input[type=range].btcpay-input-range::-ms-fill-upper{background:#f3f3f3;border:0 solid rgba(24,213,1,0);border-radius:2px;box-shadow:0 0 1.7px #020,0 0 0 #003c00}input[type=range].btcpay-input-range::-ms-thumb{box-shadow:0 0 3.7px rgba(0,170,0,0),0 0 0 rgba(0,195,0,0);border:2.5px solid #cedc21;height:22px;width:23px;border-radius:12px;background:#0f3723;cursor:pointer;height:3.1px}input[type=range].btcpay-input-range:focus::-ms-fill-lower{background:#f3f3f3}input[type=range].btcpay-input-range:focus::-ms-fill-upper{background:#fff}</style>
</script>

View File

@@ -22,7 +22,7 @@ function esc(input) {
(but it's not necessary).
Or for XML, only if the named entities are defined in its DTD.
*/
;
;
}
Vue.use(VeeValidate);
@@ -42,9 +42,42 @@ function inputChanges(event, buttonSize) {
srvModel.buttonSize = buttonSize;
}
var width = "209px";
var widthInput = "3em";
if (srvModel.buttonSize === 0) {
width = "146px";
widthInput = "2em";
} else if (srvModel.buttonSize === 1) {
width = "168px";
} else if (srvModel.buttonSize === 2) {
width = "209px";
}
var html = '<form method="POST" action="' + esc(srvModel.urlRoot) + 'api/v1/invoices">';
html += addinput("storeId", srvModel.storeId);
html += addinput("price", srvModel.price);
// Add price as hidden only if it's a fixed amount (srvModel.buttonType = 0)
if (srvModel.buttonType == 0) {
html += addinput("price", srvModel.price);
}
else if (srvModel.buttonType == 1) {
html += '\n <div style="text-align:center;width:' + width + '">';
html += '<div>';
html += addPlusMinusButton("-");
html += addInputPrice(srvModel.price, widthInput, "");
html += addPlusMinusButton("+");
html += '</div>';
html += addSelectCurrency();
html += '</div>';
}
else if (srvModel.buttonType == 2) {
html += '\n <div style="text-align:center;width:' + width + '">';
html += addInputPrice(srvModel.price, width, 'onchange="document.querySelector(\'#btcpay-input-range\').value = document.querySelector(\'#btcpay-input-price\').value"');
html += addSelectCurrency();
html += addSlider(srvModel.price, srvModel.min, srvModel.max, srvModel.step, width);
html += '</div>';
}
if (srvModel.currency) {
html += addinput("currency", srvModel.currency);
}
@@ -65,14 +98,6 @@ function inputChanges(event, buttonSize) {
html += addinput("notifyEmail", srvModel.notifyEmail);
}
var width = "209px";
if (srvModel.buttonSize === 0) {
width = "146px";
} else if (srvModel.buttonSize === 1) {
width = "168px";
} else if (srvModel.buttonSize === 2) {
width = "209px";
}
html += '\n <input type="image" src="' + esc(srvModel.payButtonImageUrl) + '" name="submit" style="width:' + width +
'" alt="Pay with BtcPay, Self-Hosted Bitcoin Payment Processor">';
@@ -93,3 +118,37 @@ function addinput(name, value) {
return html;
}
function addPlusMinusButton(type) {
var button = document.getElementById('template-button-plus-minus').innerHTML.trim();
if (type === "+") {
return button.replace(/TYPE/g, '+');
} else {
return button.replace(/TYPE/g, '-');
}
}
function addInputPrice(price, widthInput, customFn) {
var input = document.getElementById('template-input-price').innerHTML.trim();
input = input.replace(/PRICEVALUE/g, price);
input = input.replace("WIDTHINPUT", widthInput);
if (customFn) {
return input.replace("CUSTOM", customFn);
}
return input.replace("CUSTOM", "");
}
function addSelectCurrency() {
return document.getElementById('template-select-currency').innerHTML.trim();
}
function addSlider(price, min, max, step, width) {
var input = document.getElementById('template-input-slider').innerHTML.trim();
input = input.replace("PRICE", price);
input = input.replace("MIN", min);
input = input.replace("MAX", max);
input = input.replace("STEP", step);
input = input.replace("WIDTH", width);
return input;
}