mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-23 14:40:36 +01:00
466 lines
20 KiB
Text
466 lines
20 KiB
Text
@model PayButtonViewModel
|
|
@{
|
|
Layout = "../Shared/_NavLayout.cshtml";
|
|
ViewData.SetActivePageAndTitle(StoreNavPages.PayButton);
|
|
ViewData["Title"] = "Pay Button";
|
|
}
|
|
|
|
<div class="container" id="payButtonCtrl">
|
|
<div class="row">
|
|
<div class="col-lg-7">
|
|
<div class="form-row">
|
|
<div class="form-group col-md-8">
|
|
<label>Price</label>
|
|
<input name="price" type="text" class="form-control"
|
|
v-model="srvModel.price" v-on:change="inputChanges"
|
|
v-validate="'required|decimal|min_value:0'" :class="{'is-invalid': errors.has('price') }">
|
|
<small class="text-danger">{{ errors.first('price') }}</small>
|
|
</div>
|
|
<div class="form-group col-md-4" v-if="!srvModel.appIdEndpoint">
|
|
<label> </label>
|
|
<input name="currency" type="text" class="form-control"
|
|
v-model="srvModel.currency" v-on:change="inputChanges"
|
|
:class="{'is-invalid': errors.has('currency') }">
|
|
</div>
|
|
</div>
|
|
<div class="form-group" v-if="!srvModel.appIdEndpoint">
|
|
<label>Checkout Description</label>
|
|
<input name="checkoutDesc" type="text" class="form-control" placeholder="(optional)"
|
|
v-model="srvModel.checkoutDesc" v-on:change="inputChanges">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Order Id</label>
|
|
<input name="orderId" type="text" class="form-control" id="inputAddress" placeholder="(optional)"
|
|
v-model="srvModel.orderId" v-on:change="inputChanges">
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-5">
|
|
<br />
|
|
Set parameters that define the purchase: price, currency and an optional description of purchase.
|
|
<br /><br />
|
|
Generated HTML will be displayed at the bottom of this page and all you need is to paste that HTML into your final page.
|
|
Clicking on the button will redirect customer to checkout.
|
|
</div>
|
|
</div>
|
|
<hr />
|
|
<h3>Pay button display options</h3>
|
|
<br />
|
|
<div class="row">
|
|
<div class="col-lg-7">
|
|
<div class="form-group" v-if="!srvModel.appIdEndpoint">
|
|
<label>
|
|
<input type="checkbox" v-model="srvModel.useModal" v-on:change="inputChanges" class="form-check-inline"/>Use Modal
|
|
</label>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>
|
|
<input type="checkbox" v-model="buttonInlineTextMode" v-on:change="inputChanges" class="form-check-inline"/> Customize text in button
|
|
</label>
|
|
</div>
|
|
<div class="form-group" v-show="buttonInlineTextMode">
|
|
<label>Pay Button Text</label>
|
|
<input name="payButtonText" type="text" class="form-control" id="inputAddress"
|
|
v-model="srvModel.payButtonText" v-on:change="inputChanges">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Pay Button Image Url</label>
|
|
<input name="payButtonImageUrl" type="text" class="form-control" id="inputAddress"
|
|
v-model="srvModel.payButtonImageUrl" v-on:change="inputChanges"
|
|
v-validate="{ required: this.imageUrlRequired, url: {require_tld:false} }"
|
|
:class="{'is-invalid': errors.has('payButtonImageUrl') }">
|
|
<small class="text-danger">{{ errors.first('payButtonImageUrl') }}</small>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Image Size</label>
|
|
<div style="vertical-align:top; font-size:12px; display:flex;">
|
|
<button class="btn text-nowrap" style="width:146px;height:40px;margin-right:40px;"
|
|
v-on:click="inputChanges($event, 0)" v-bind:class="{'btn-primary': (srvModel.buttonSize == 0) }">
|
|
146 x 40 px
|
|
</button>
|
|
<button class="btn text-nowrap btn-default" style="width:168px;height:46px;margin-right:40px;"
|
|
v-on:click="inputChanges($event, 1)" v-bind:class="{'btn-primary': (srvModel.buttonSize == 1) }">
|
|
168 x 46 px
|
|
</button>
|
|
<button class="btn text-nowrap btn-default" style="width:209px;height:57px;"
|
|
v-on:click="inputChanges($event, 2)" v-bind:class="{'btn-primary': (srvModel.buttonSize == 2) }">
|
|
209 x 57 px
|
|
</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 == 1 ||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 class="form-group" v-if="srvModel.buttonType == 1">
|
|
<div class="form-check">
|
|
<input name="simpleInput"
|
|
id="simpleInput"
|
|
type="checkbox"
|
|
class="form-check-input"
|
|
v-model="srvModel.simpleInput"
|
|
v-on:change="inputChanges"
|
|
:class="{'is-invalid': errors.has('simpleInput') }">
|
|
<label class="form-check-label" for="simpleInput">Use a simple input style</label>
|
|
<small class="text-danger">{{ errors.first('simpleInput') }}</small>
|
|
</div>
|
|
<div class="form-check">
|
|
<input name="fitButtonInline"
|
|
id="fitButtonInline"
|
|
type="checkbox"
|
|
class="form-check-input"
|
|
v-model="srvModel.fitButtonInline"
|
|
v-on:change="inputChanges"
|
|
:class="{'is-invalid': errors.has('fitButtonInline') }">
|
|
<label class="form-check-label" for="fitButtonInline">Fit button inline</label>
|
|
<small class="text-danger">{{ errors.first('fitButtonInline') }}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-5">
|
|
<h4>Preview</h4>
|
|
<div id="preview"></div>
|
|
</div>
|
|
</div>
|
|
<hr />
|
|
<h3>Payment Notifications</h3>
|
|
<br />
|
|
<div class="row">
|
|
<div class="col-lg-7">
|
|
<div class="form-group">
|
|
<label>Server IPN</label>
|
|
<input name="serverIpn" type="text" class="form-control" placeholder="(optional)"
|
|
v-model="srvModel.serverIpn" v-on:change="inputChanges"
|
|
v-validate="'url'" :class="{'is-invalid': errors.has('serverIpn') }">
|
|
<small class="text-danger">{{ errors.first('serverIpn') }}</small>
|
|
</div>
|
|
<div class="form-group" v-if="!srvModel.appIdEndpoint">
|
|
<label>Send Email Notifications to</label>
|
|
<input name="notifyEmail" type="text" class="form-control" placeholder="(optional)"
|
|
v-model="srvModel.notifyEmail" v-on:change="inputChanges"
|
|
v-validate="'email'" :class="{'is-invalid': errors.has('notifyEmail') }">
|
|
<small class="text-danger">{{ errors.first('notifyEmail') }}</small>
|
|
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Browser Redirect</label>
|
|
<input name="browserRedirect" type="text" class="form-control" placeholder="(optional)"
|
|
v-model="srvModel.browserRedirect" v-on:change="inputChanges"
|
|
v-validate="'url'" :class="{'is-invalid': errors.has('browserRedirect') }">
|
|
<small class="text-danger">{{ errors.first('browserRedirect') }}</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-5">
|
|
<br />
|
|
These parameters allow you to influence the process after purchase. <i>Server IPN</i> is the URL to which we'll post purchase data.
|
|
We can also deliver an email notification to a specified address.
|
|
<br /><br />
|
|
Finally, <i>Browser Redirect</i> defines where BTCPayServer will redirect the customer after purchase is completed.
|
|
</div>
|
|
</div>
|
|
<h3>Advanced</h3>
|
|
<br />
|
|
<div class="row" v-if="!srvModel.appIdEndpoint">
|
|
<div class="col-lg-7">
|
|
<div class="form-group">
|
|
<label>Checkout Additional Query String</label>
|
|
<input name="checkoutQueryString" type="text" class="form-control" placeholder="(optional)"
|
|
v-model="srvModel.checkoutQueryString" v-on:change="inputChanges"
|
|
:class="{'is-invalid': errors.has('checkoutQueryString') }">
|
|
<small class="text-danger">{{ errors.first('checkoutQueryString') }}</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-5">
|
|
<br />
|
|
This parameter allows you to specify additional query string parameters that should be appended to the checkout page once the invoice is created. For example, <kbd>lang=da-DK</kbd> would load the checkout page in Danish by default.
|
|
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-lg-7">
|
|
<div class="form-group">
|
|
<label>Use App as endpoint</label>
|
|
<select v-model="srvModel.appIdEndpoint" v-on:change="inputChanges" class="form-control">
|
|
<option value="">Use default pay button endpoint</option>
|
|
<option v-for="app in srvModel.apps" v-bind:value="app.id" >{{app.appName}} ({{app.appType}})</option>
|
|
</select>
|
|
<small class="text-danger">{{ errors.first('appIdEndpoint') }}</small>
|
|
</div>
|
|
<div class="form-group" v-if="srvModel.appIdEndpoint">
|
|
<label>App Item/Perk</label>
|
|
<input name="appChoiceKey" type="text" class="form-control" placeholder="(optional)"
|
|
v-model="srvModel.appChoiceKey" v-on:change="inputChanges"
|
|
:class="{'is-invalid': errors.has('appChoiceKey') }">
|
|
<small class="text-danger">{{ errors.first('appChoiceKey') }}</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-5">
|
|
<br />
|
|
This allows you to link this pay button to an app instead. Some features are disabled due to the different endpoint capabilities. You can set which perk/item this button should be targeting.
|
|
|
|
</div>
|
|
</div>
|
|
<hr />
|
|
<br />
|
|
|
|
<h3>Generated code</h3>
|
|
<div class="row" v-show="!errors.any()">
|
|
<div class="col-lg-12">
|
|
<pre><code id="mainCode" class="html"></code></pre>
|
|
<button class="btn btn-primary" id="copyCode">
|
|
<i class="fa fa-copy"></i> Copy Code
|
|
</button>
|
|
<span class="copyLabelPopup" style="display:none;">Copied</span>
|
|
</div>
|
|
</div>
|
|
<div class="row" v-show="errors.any()">
|
|
<div class="col-lg-12 text-danger">
|
|
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" asp-append-version="true">
|
|
<script src="~/vendor/highlightjs/highlight.min.js" asp-append-version="true"></script>
|
|
|
|
<script src="~/vendor/vuejs/vue.js" asp-append-version="true"></script>
|
|
<script src="~/vendor/vuejs-vee-validate/vee-validate.js" asp-append-version="true"></script>
|
|
|
|
<script src="~/vendor/clipboard.js/clipboard.js" asp-append-version="true"></script>
|
|
|
|
<script src="~/paybutton/paybutton.js" asp-append-version="true"></script>
|
|
}
|
|
|
|
@section Scripts {
|
|
<script type="text/javascript">
|
|
var srvModel = @Safe.Json(Model);
|
|
|
|
var payButtonCtrl = new Vue({
|
|
el: '#payButtonCtrl',
|
|
data: {
|
|
srvModel: srvModel,
|
|
originalButtonImageUrl: srvModel.payButtonImageUrl,
|
|
buttonInlineTextMode: false
|
|
},
|
|
computed: {
|
|
imageUrlRequired: function(){
|
|
return !this.buttonInlineTextMode;
|
|
}
|
|
},
|
|
methods: {
|
|
inputChanges: function (event, buttonSize) {
|
|
inputChanges(event, buttonSize);
|
|
}
|
|
|
|
},
|
|
watch: {
|
|
buttonInlineTextMode: function (checked) {
|
|
if(!checked){
|
|
this.srvModel.payButtonText = "";
|
|
this.srvModel.payButtonImageUrl = this.originalButtonImageUrl;
|
|
}else {
|
|
this.srvModel.payButtonText = "Pay with";
|
|
this.srvModel.payButtonImageUrl = this.srvModel.urlRoot + "img/logo.svg";
|
|
}
|
|
this.inputChanges();
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
}
|
|
|
|
<script id="template-paybutton-styles" type="text/template">
|
|
<style type="text/css">
|
|
.btcpay-form {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.btcpay-form--inline {
|
|
flex-direction: row;
|
|
}
|
|
.btcpay-form--block {
|
|
flex-direction: column;
|
|
}
|
|
.btcpay-form--inline .submit {
|
|
margin-left: 15px;
|
|
}
|
|
.btcpay-form--block select {
|
|
margin-bottom: 10px;
|
|
}
|
|
.btcpay-form .btcpay-custom-container{
|
|
text-align: center;
|
|
}
|
|
.btcpay-custom {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.btcpay-form .plus-minus {
|
|
cursor:pointer;
|
|
font-size:25px;
|
|
line-height: 25px;
|
|
background: #DFE0E1;
|
|
height: 30px;
|
|
width: 45px;
|
|
border:none;
|
|
border-radius: 60px;
|
|
margin: auto 5px;
|
|
display: inline-flex;
|
|
justify-content: center;
|
|
}
|
|
.btcpay-form select {
|
|
-moz-appearance: none;
|
|
-webkit-appearance: none;
|
|
appearance: none;
|
|
color: currentColor;
|
|
background: transparent;
|
|
border:1px solid transparent;
|
|
display: block;
|
|
padding: 1px;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
font-size: 11px;
|
|
cursor: pointer;
|
|
}
|
|
.btcpay-form select:hover {
|
|
border-color: #ccc;
|
|
}
|
|
#btcpay-input-price {
|
|
-moz-appearance: none;
|
|
-webkit-appearance: none;
|
|
border: none;
|
|
box-shadow: none;
|
|
text-align: center;
|
|
font-size: 25px;
|
|
margin: auto;
|
|
border-radius: 5px;
|
|
line-height: 35px;
|
|
background: #fff;
|
|
}
|
|
</style>
|
|
</script>
|
|
|
|
<script id="template-slider-styles" type="text/template">
|
|
<style type="text/css">
|
|
input[type=range].btcpay-input-range {
|
|
-webkit-appearance:none;
|
|
width:100%;
|
|
background: transparent;
|
|
}
|
|
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;
|
|
}
|
|
input[type=range].btcpay-input-range::-webkit-slider-thumb {
|
|
box-shadow:none;
|
|
border:2.5px solid #cedc21;
|
|
height:22px;
|
|
width:22px;
|
|
border-radius:50%;
|
|
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;
|
|
}
|
|
input[type=range].btcpay-input-range::-moz-range-thumb {
|
|
box-shadow:none;
|
|
border:2.5px solid #cedc21;
|
|
height:22px;
|
|
width:22px;
|
|
border-radius:50%;
|
|
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;
|
|
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;
|
|
border-radius:2px;
|
|
box-shadow:0 0 1.7px #020,0 0 0 #003c00;
|
|
}
|
|
input[type=range].btcpay-input-range::-ms-thumb {
|
|
box-shadow:none;
|
|
border:2.5px solid #cedc21;
|
|
height:22px;
|
|
width:22px;
|
|
border-radius:50%;
|
|
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>
|