btcpayserver/BTCPayServer/Views/Stores/PayButton.cshtml

476 lines
21 KiB
Plaintext
Raw Normal View History

@model PayButtonViewModel
2018-08-10 20:26:51 +02:00
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData.SetActivePageAndTitle(StoreNavPages.PayButton, "Pay Button", Context.GetStoreData().StoreName);
2018-08-10 20:26:51 +02:00
}
Bootstrap v5 migration (#2490) * Swap bootstrap asset files * Update themes and color definitions * Move general bootstrap customizations * Theme updates Theme updates * Remove BuildBundlerMinifier This lead to an error, because BuildBundlerMinifier and BundlerMinifier.Core seem to conflict here. Details: https://stackoverflow.com/a/61119586 * Rewplace btn-block class with w-100 * Update badge classes * Remove old font family head variable * Update margin classes * Cleanups * Update float classes * Update text classes * Update padding classes * Update border classes * UPdate dropdown classes * Update select classes * Update neutral custom props * Update bootstrap and customizations * Update ChromeDriver; disable smooth scroll https://github.com/SeleniumHQ/selenium/issues/8295 * Improve alert messages * Improve bootstrap customizations * Disable reduced motion See also 7358282f * Update Bootstrap data attributes * Update file inputs * Update input groups * Replace deprecated jumbotron class * Update variables; re-add negative margin util classes * Update cards * Update form labels * Debug alerts * Fix aria-labelledby associations * Dropdown-related test fixes * Fix CanUseWebhooks test * Test fixes * Nav updates * Fix nav usage in wallet send and payouts * Update alert and modal close buttons * Re-add backdrop properties * Upgrade Bootstrap to v5 final * Update screen reader classes * Update font-weight classes * Update monospace font classes * Update accordians * Update close icon usage * Cleanup * Update scripts and style integrations * Update input group texts * Update LN node setup page * Update more form control classes * Update inline forms * Add js specific test * Upgrade Vue.js * Remove unused JS * Upgrade Bootstrap to v5.0.1 * Try container related test updates * Separate jQuery bundle * Remove jQuery from LND seed backup page * Remove unused code * Refactor email autofill js * Refactor camera scanner JS * Re-add tests * Re-add BuildBundlerMinifier * Do not minify bundles containing Bootstrap Details https://github.com/madskristensen/BundlerMinifier/issues/558 * Update bundles * Cleanup JS test * Cleanup tests involving dropdowns * Cleanup tests involving collapses * Cleanup locale additions in ConfigureCore * Cleanup bundles * Remove duplicate status message * Cleanup formatting * Fix missing validation scripts * Remove unused unminified Bootstrap js files * Fix classic theme * Fix Casa theme * Fix PoS validation
2021-05-19 04:39:27 +02:00
@section PageHeadContent {
<link rel="stylesheet" href="~/vendor/highlightjs/default.min.css" asp-append-version="true">
}
@section PageFootContent {
<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>
<script>
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>
}
<div id="payButtonCtrl">
<div class="row">
<div class="col-lg-7">
<h4 class="mb-3">@ViewData["PageTitle"]</h4>
<div class="row">
<div class="form-group col-md-8">
<label class="form-label">Price</label>
2021-08-03 10:03:00 +02:00
<input name="price" type="text" class="form-control" placeholder="(optional)"
v-model="srvModel.price" v-on:change="inputChanges"
2021-08-03 10:03:00 +02:00
v-validate="'decimal|min_value:0'" :class="{'is-invalid': errors.has('price') }">
<small class="text-danger">{{ errors.first('price') }}</small>
2018-08-10 20:26:51 +02:00
</div>
<div class="form-group col-md-4" v-if="!srvModel.appIdEndpoint">
<label class="form-label">&nbsp;</label>
2019-04-04 21:32:16 +02:00
<input name="currency" type="text" class="form-control"
v-model="srvModel.currency" v-on:change="inputChanges"
:class="{'is-invalid': errors.has('currency') }">
2018-08-10 20:26:51 +02:00
</div>
</div>
<div class="form-group" v-if="!srvModel.appIdEndpoint">
<label class="form-label">Checkout Description</label>
<input name="checkoutDesc" type="text" class="form-control" placeholder="(optional)"
v-model="srvModel.checkoutDesc" v-on:change="inputChanges">
2018-08-10 20:26:51 +02:00
</div>
<div class="form-group">
<label class="form-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>
<h4 class="mt-5 mb-3">Pay button display options</h4>
<div class="row">
<div class="col-lg-7">
<div class="form-group">
<div class="form-check" v-if="!srvModel.appIdEndpoint">
<input id="useModal" type="checkbox" v-model="srvModel.useModal" v-on:change="inputChanges" class="form-check-input"/>
<label for="useModal" class="form-check-label">Use Modal</label>
</div>
<div class="form-check">
<input id="buttonInlineTextMode" type="checkbox" v-model="buttonInlineTextMode" v-on:change="inputChanges" class="form-check-input"/>
<label for="buttonInlineTextMode" class="form-check-label">Customize text in button</label>
</div>
</div>
<div class="form-group" v-show="buttonInlineTextMode">
<label class="form-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 class="form-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 class="form-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 class="form-label">Button Type</label>
<div class="form-check">
<input class="form-check-input" type="radio" name="button-type" id="btn-fixed" value="0" v-model="srvModel.buttonType" v-on:change="inputChanges" checked/>
<label for="btn-fixed" class="form-check-label">Fixed amount</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="button-type" id="btn-custom" value="1" v-model="srvModel.buttonType" v-on:change="inputChanges"/>
<label for="btn-custom" class="form-check-label">Custom amount</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="button-type" id="btn-slider" value="2" v-model="srvModel.buttonType" v-on:change="inputChanges"/>
<label for="btn-slider" class="form-check-label">Slider</label>
2019-04-04 20:56:12 +02:00
</div>
</div>
<div class="row" v-if="srvModel.buttonType == 1 ||srvModel.buttonType == 2">
<div class="form-group col-md-4">
<label class="form-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:0'" :class="{'is-invalid': errors.has('min') }">
<small class="text-danger">{{ errors.first('min') }}</small>
</div>
<div class="form-group col-md-4">
<label class="form-label">Max</label>
<input name="max" type="text" class="form-control"
v-model="srvModel.max" v-on:change="inputChanges"
v-validate="'required|decimal'" :class="{'is-invalid': errors.has('max') }">
<small class="text-danger">{{ errors.first('max') }}</small>
</div>
<div class="form-group col-md-4">
<label class="form-label">Step</label>
<input name="step" type="text" class="form-control"
v-model="srvModel.step" v-on:change="inputChanges"
v-validate="'required'" :class="{'is-invalid': errors.has('step') }">
<small class="text-danger">{{ errors.first('step') }}</small>
</div>
</div>
<template 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>
</template>
</div>
<div class="col-lg-5">
<h5 class="mb-3">Preview</h5>
<div id="preview"></div>
<div v-show="!srvModel.appIdEndpoint">
<h5 class="mt-4 mb-3">Link</h5>
<span>Alternatively, you can share this link or encode it in a QR code</span>
<div id="preview-link"></div>
</div>
</div>
</div>
<h4 class="mt-5 mb-3">Payment Notifications</h4>
<div class="row">
<div class="col-lg-7">
<div class="form-group">
<label class="form-label">Server IPN</label>
<input name="serverIpn" type="text" class="form-control" placeholder="(optional)"
v-model="srvModel.serverIpn" v-on:change="inputChanges"
2018-08-23 04:12:25 +02:00
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 class="form-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 class="form-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>
<h4 class="mt-5 mb-3">Advanced options</h4>
<div class="row" v-if="!srvModel.appIdEndpoint">
<div class="col-lg-7">
<div class="form-group">
<label class="form-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, <code>lang=da-DK</code> would load the checkout page in Danish by default.
</div>
</div>
<div class="row">
<div class="col-lg-7">
<div class="form-group">
<label class="form-label">Use App as endpoint</label>
Bootstrap v5 migration (#2490) * Swap bootstrap asset files * Update themes and color definitions * Move general bootstrap customizations * Theme updates Theme updates * Remove BuildBundlerMinifier This lead to an error, because BuildBundlerMinifier and BundlerMinifier.Core seem to conflict here. Details: https://stackoverflow.com/a/61119586 * Rewplace btn-block class with w-100 * Update badge classes * Remove old font family head variable * Update margin classes * Cleanups * Update float classes * Update text classes * Update padding classes * Update border classes * UPdate dropdown classes * Update select classes * Update neutral custom props * Update bootstrap and customizations * Update ChromeDriver; disable smooth scroll https://github.com/SeleniumHQ/selenium/issues/8295 * Improve alert messages * Improve bootstrap customizations * Disable reduced motion See also 7358282f * Update Bootstrap data attributes * Update file inputs * Update input groups * Replace deprecated jumbotron class * Update variables; re-add negative margin util classes * Update cards * Update form labels * Debug alerts * Fix aria-labelledby associations * Dropdown-related test fixes * Fix CanUseWebhooks test * Test fixes * Nav updates * Fix nav usage in wallet send and payouts * Update alert and modal close buttons * Re-add backdrop properties * Upgrade Bootstrap to v5 final * Update screen reader classes * Update font-weight classes * Update monospace font classes * Update accordians * Update close icon usage * Cleanup * Update scripts and style integrations * Update input group texts * Update LN node setup page * Update more form control classes * Update inline forms * Add js specific test * Upgrade Vue.js * Remove unused JS * Upgrade Bootstrap to v5.0.1 * Try container related test updates * Separate jQuery bundle * Remove jQuery from LND seed backup page * Remove unused code * Refactor email autofill js * Refactor camera scanner JS * Re-add tests * Re-add BuildBundlerMinifier * Do not minify bundles containing Bootstrap Details https://github.com/madskristensen/BundlerMinifier/issues/558 * Update bundles * Cleanup JS test * Cleanup tests involving dropdowns * Cleanup tests involving collapses * Cleanup locale additions in ConfigureCore * Cleanup bundles * Remove duplicate status message * Cleanup formatting * Fix missing validation scripts * Remove unused unminified Bootstrap js files * Fix classic theme * Fix Casa theme * Fix PoS validation
2021-05-19 04:39:27 +02:00
<select v-model="srvModel.appIdEndpoint" v-on:change="inputChanges" class="form-select">
<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>
<h4 class="mt-5 mb-3">Generated code</h4>
<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>
2018-08-10 20:26:51 +02:00
</div>
</div>
2019-10-31 11:31:30 +01:00
<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 {
2019-10-31 11:31:30 +01:00
display: flex;
align-items: center;
justify-content: center;
}
.btcpay-form .plus-minus {
cursor:pointer;
font-size:25px;
line-height: 25px;
background: #DFE0E1;
2019-10-31 11:31:30 +01:00
height: 30px;
width: 45px;
border:none;
border-radius: 60px;
margin: auto 5px;
display: inline-flex;
justify-content: center;
2019-10-31 11:31:30 +01:00
}
.btcpay-form select {
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
color: currentColor;
2019-10-31 11:31:30 +01:00
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;
}
#btcpay-input-price::-webkit-outer-spin-button,
#btcpay-input-price::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
2019-10-31 11:31:30 +01:00
</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;
2019-10-31 11:31:30 +01:00
}
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;
2019-10-31 11:31:30 +01:00
}
input[type=range].btcpay-input-range::-webkit-slider-thumb {
box-shadow:none;
2019-10-31 11:31:30 +01:00
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;
2019-10-31 11:31:30 +01:00
}
input[type=range].btcpay-input-range::-moz-range-thumb {
box-shadow:none;
2019-10-31 11:31:30 +01:00
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;
2019-10-31 11:31:30 +01:00
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;
2019-10-31 11:31:30 +01:00
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;
2019-10-31 11:31:30 +01:00
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>