Payment Request UI: Layout and header

This commit is contained in:
Dennis Reimann 2020-09-25 18:08:45 +02:00
parent 2a3dbaa7b4
commit 4d4459fa4e
No known key found for this signature in database
GPG key ID: 5009E1797F03F8D0
7 changed files with 174 additions and 189 deletions

View file

@ -147,7 +147,8 @@
}
</td>
</tr>
}else if (Model.Archived)
}
else if (Model.Archived)
{
<tr>
<td colspan="4" class="text-center">
@ -162,13 +163,6 @@
</div>
</div>
<div class="card-footer text-muted d-flex justify-content-between">
<div >Updated @Model.LastUpdated.ToString("g")</div>
<div >
<span class="text-muted">Powered by </span><a href="https://btcpayserver.org" target="_blank">BTCPay Server</a>
</div>
</div>
</div>
</div>
</div>

View file

@ -12,96 +12,162 @@
<head>
<title>@Model.Title</title>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex,nofollow">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<link href="@Context.Request.GetRelativePathOrAbsolute(themeManager.BootstrapUri)" rel="stylesheet" />
<link href="@Context.Request.GetRelativePathOrAbsolute(themeManager.ThemeUri)" rel="stylesheet" />
<bundle name="wwwroot/bundles/payment-request-bundle.min.css" asp-append-version="true"></bundle>
@if (Model.CustomCSSLink != null)
{
<link href="@Model.CustomCSSLink" rel="stylesheet" />
}
@if (!Context.Request.Query.ContainsKey("simple"))
{
<script type="text/javascript">
var srvModel = @Safe.Json(Model);
</script>
<bundle name="wwwroot/bundles/payment-request-bundle-1.min.js" asp-append-version="true"></bundle>
<bundle name="wwwroot/bundles/payment-request-bundle-2.min.js" asp-append-version="true"></bundle>
@*We need to make sure btcpay.js is not bundled, else it will not work if there is a RootPath*@
<script src="~/modal/btcpay.js" asp-append-version="true"></script>
}
<bundle name="wwwroot/bundles/payment-request-bundle.min.css" asp-append-version="true"></bundle>
<script type="text/javascript">
var srvModel = @Safe.Json(Model);
</script>
<bundle name="wwwroot/bundles/payment-request-bundle.min.js" asp-append-version="true"></bundle>
@*We need to make sure btcpay.js is not bundled, else it will not work if there is a RootPath*@
<script src="~/modal/btcpay.js" asp-append-version="true"></script>
@Safe.Raw(Model.EmbeddedCSS)
</head>
<body>
<partial name="_StatusMessage" />
@if (Context.Request.Query.ContainsKey("simple"))
{
@await Html.PartialAsync("MinimalPaymentRequest", Model)
}
else
{
<noscript>
@await Html.PartialAsync("MinimalPaymentRequest", Model)
</noscript>
<div class="container" id="app" v-cloak>
<div class="row w-100 p-0 m-0" style="height: 100vh">
<div class="mx-auto my-auto w-100">
<div class="card">
<h1 class="card-header px-3">
{{srvModel.title}}
<span class="text-muted float-right text-center">
<template v-if="settled">Settled</template>
<template v-else>
<template v-if="ended">Request Expired</template>
<template v-else-if="endDiff">Expires in {{endDiff}}</template>
<template v-else>{{srvModel.status}}</template>
</template>
</span>
</h1>
<div class="card-body px-0 pt-0 pb-0">
<body class="h-100">
<div id="app" class="h-100 d-flex flex-column">
<nav id="mainNav" class="navbar sticky-top py-3 py-lg-4">
<div class="container">
<div class="row align-items-center" style="width:calc(100% + 30px)">
<div class="col-12 col-md-8 col-lg-9 col-xl-10">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<table class="table table-light mb-0">
<tbody>
<tr>
<td class="px-3 h2 text-muted">Request amount:</td>
<td class="px-3 h2 text-nowrap text-right">{{srvModel.amountFormatted}}</td>
</tr>
<tr>
<td class="px-3 h2 text-muted">Paid so far:</td>
<td class="px-3 h2 text-nowrap text-right">{{srvModel.amountCollectedFormatted}}</td>
</tr>
<tr>
<td class="px-3 h2 text-muted">Amount due:</td>
<td class="px-3 h2 text-nowrap text-right">{{srvModel.amountDueFormatted}}</td>
</tr>
</tbody>
</table>
<div
v-if="srvModel.description && srvModel.description !== '' && srvModel.description !== '<br>'"
v-html="srvModel.description"
class="w-100 px-3 pt-4 pb-3"
></div>
<div class="col col-12 col-lg-8">
<h1 class="h3" v-bind="srvModel.title">@Model.Title</h1>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="table-responsive">
<table class="table table-light border-top-0 ">
<thead>
<div class="col col-12 col-sm-7 col-lg-8 d-flex align-items-center">
<span class="text-muted">Last Updated</span>
&nbsp;
<span v-bind="lastUpdated">@Model.LastUpdated.ToString("g")</span>
<button type="button" class="btn btn-link d-none d-lg-inline-block d-print-none border-0 p-0 ml-4" v-on:click="window.print" v-cloak>
Print
</button>
<button type="button" class="btn btn-link d-none d-lg-inline-block d-print-none border-0 p-0 ml-4" v-on:click="copyLink" v-cloak>
Copy Link
</button>
</div>
<div class="col col-12 col-sm-5 text-sm-right col-lg-4 mt-lg-n4 pt-lg-1">
<noscript>@Model.Status</noscript>
<template v-if="settled">Settled</template>
<template v-else-if="ended">Request Expired</template>
<template v-else-if="endDiff"><span class="text-muted">Expires in</span> {{endDiff}}</template>
<template v-else>{{srvModel.status}}</template>
</div>
</div>
</div>
<div class="col-12 pt-4 pb-2 col-md-4 py-md-0 col-lg-3 col-xl-2">
<template v-if="srvModel.archived">
<div class="h3">
<span class="badge badge-secondary">Archived</span>
</div>
</template>
<template v-else-if="!ended && (srvModel.amountDue) > 0" class="d-print-none">
<template v-if="srvModel.allowCustomPaymentAmounts && !srvModel.anyPendingInvoice">
<form v-on:submit="submitCustomAmountForm">
<div class="input-group m-auto" style="max-width: 250px">
<input
:readonly="!srvModel.allowCustomPaymentAmounts"
class="form-control"
type="number"
v-model="customAmount"
:max="srvModel.amountDue"
step="any"
placeholder="Amount"
required>
<div class="input-group-append">
<span class='input-group-text'>{{currency}}</span>
<button
class="btn btn-primary btn-lg d-inline-block w-100"
v-bind:class="{ 'btn-disabled': loading}"
:disabled="loading"
type="submit">
<div v-if="loading" class="spinner-grow spinner-grow-sm" role="status">
<span class="sr-only">Loading...</span>
</div>
Pay Invoice
</button>
</div>
</div>
</form>
</template>
<template v-else>
<button class="btn btn-primary btn-lg w-100 d-flex align-items-center justify-content-center" v-on:click="pay(null)" :disabled="loading">
<div v-if="loading" class="spinner-grow spinner-grow-sm mr-2" role="status">
<span class="sr-only">Loading...</span>
</div>
<span>Pay Invoice</span>
</button>
<button class="btn btn-outline-secondary mt-2 w-100 d-flex align-items-center justify-content-center" v-if="srvModel.anyPendingInvoice && !srvModel.pendingInvoiceHasPayments" v-on:click="cancelPayment()" :disabled="loading">
<span v-if="loading" class="spinner-grow spinner-grow-sm mr-2" role="status">
<span class="sr-only">Loading...</span>
</span>
<span>Cancel Invoice</span>
</button>
</template>
</template>
</div>
</div>
</div>
</nav>
<main class="flex-grow-1 py-4">
<div class="container">
<div class="row" style="margin-bottom:30px;">
<partial name="_StatusMessage"/>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="jumbotron h-100 p-sm-5">
<h2 class="h4 mb-3">Invoice Summary</h2>
<div v-html="srvModel.description">
@if (Model.Description != null && Model.Description != "" && Model.Description != "<br>")
{
@Safe.Raw(Model.Description)
}
</div>
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="jumbotron h-100 p-sm-5">
<h2 class="h4 mb-3">Payment Details</h2>
<table class="table">
<tbody>
<tr>
<td class="px-3 h2 text-muted">Request amount:</td>
<td class="px-3 h2 text-nowrap text-right">{{srvModel.amountFormatted}}</td>
</tr>
<tr>
<td class="px-3 h2 text-muted">Paid so far:</td>
<td class="px-3 h2 text-nowrap text-right">{{srvModel.amountCollectedFormatted}}</td>
</tr>
<tr>
<td class="px-3 h2 text-muted">Amount due:</td>
<td class="px-3 h2 text-nowrap text-right">{{srvModel.amountDueFormatted}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="jumbotron h-100 p-sm-5">
<h2 class="h4 mb-3">Payment History</h2>
<div class="table-responsive">
<table class="table border-top-0">
<thead>
<tr>
<th class="border-top-0" scope="col">Invoice #</th>
<th class="border-top-0">Price</th>
<th class="border-top-0">Expiry</th>
<th class="border-top-0">Status</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
<tr v-if="!srvModel.invoices || srvModel.invoices.length == 0">
<td colspan="4" class="text-center">No payments made yet</td>
</tr>
@ -144,85 +210,19 @@ else
</td>
</tr>
</template>
<tr v-if="srvModel.archived">
<td colspan="4" class="text-center">
<button type="button" class="btn btn-secondary" disabled>Archived</button>
</td>
</tr>
<tr v-else-if="!ended && (srvModel.amountDue) > 0" class="d-print-none">
<td colspan="4" class="text-center">
<template v-if="srvModel.allowCustomPaymentAmounts && !srvModel.anyPendingInvoice">
<form v-on:submit="submitCustomAmountForm">
<div class="input-group m-auto" style="max-width: 250px">
<input
:readonly="!srvModel.allowCustomPaymentAmounts"
class="form-control"
type="number"
v-model="customAmount"
:max="srvModel.amountDue"
step="any"
placeholder="Amount"
required>
<div class="input-group-append">
<span class='input-group-text'>{{currency}}</span>
<button
class="btn btn-primary"
v-bind:class="{ 'btn-disabled': loading}"
:disabled="loading"
type="submit">
<div v-if="loading" class="spinner-grow spinner-grow-sm" role="status">
<span class="sr-only">Loading...</span>
</div>
Pay now
</button>
</div>
</div>
</form>
</template>
<template v-else>
<button class="btn btn-primary btn-lg mt-1" v-on:click="pay(null)"
:disabled="loading">
<div v-if="loading" class="spinner-grow spinner-grow-sm" role="status">
<span class="sr-only">Loading...</span>
</div>
Pay now
</button>
<button class="btn btn-secondary btn-lg mt-1"
v-if="srvModel.anyPendingInvoice && !srvModel.pendingInvoiceHasPayments"
v-on:click="cancelPayment()"
:disabled="loading">
<div v-if="loading" class="spinner-grow spinner-grow-sm" role="status">
<span class="sr-only">Loading...</span>
</div>
Cancel current invoice</button>
</template>
</td>
</tr>
</tbody>
</table>
</div>
</tbody>
</table>
</div>
</div>
</div>
<div class="card-footer text-muted d-flex justify-content-between">
<div>
<span v-on:click="print" class="btn-link d-print-none" style="cursor: pointer"> <span class="fa fa-print"></span> Print</span>
<span>Updated {{lastUpdated}}</span>
</div>
<div>
<span class="text-muted">Powered by </span><a href="https://btcpayserver.org" target="_blank">BTCPay Server</a>
</div>
</div>
</div>
</div>
</div>
</main>
<footer class="pt-2 pb-4">
<div class="container text-center">
Powered by <a href="https://btcpayserver.org" target="_blank">BTCPay Server</a>
</div>
</footer>
</div>
}
</body>
</html>

View file

@ -13,20 +13,10 @@
@RenderSection("HeadScripts", required: false)
@RenderSection("HeaderContent", false)
<noscript>
<style>
.hide-when-js {
display: block !important;
}
.only-for-js {
display: none !important;
}
[v-cloak]::before {
content: "" !important;
}
.hide-when-js { display: block !important; }
.only-for-js { display: none !important; }
</style>
</noscript>
</head>

View file

@ -166,7 +166,7 @@
]
},
{
"outputFileName": "wwwroot/bundles/payment-request-bundle-1.min.js",
"outputFileName": "wwwroot/bundles/payment-request-bundle.min.js",
"inputFiles": [
"wwwroot/vendor/vuejs/vue.min.js",
"wwwroot/vendor/babel-polyfill/polyfill.min.js",
@ -174,13 +174,8 @@
"wwwroot/vendor/bootstrap-vue/bootstrap-vue.js",
"wwwroot/vendor/signalr/signalr.js",
"wwwroot/vendor/animejs/anime.min.js",
"wwwroot/vendor/moment/moment.min.js",
"wwwroot/payment-request/**/*.js"
]
},
{
"outputFileName": "wwwroot/bundles/payment-request-bundle-2.min.js",
"inputFiles": [
"wwwroot/vendor/moment/moment.min.js"
],
"minify": {
"enabled": false
@ -191,7 +186,7 @@
"inputFiles": [
"wwwroot/vendor/font-awesome/css/font-awesome.min.css",
"wwwroot/vendor/bootstrap-vue/bootstrap-vue.css",
"wwwroot/payment-request/**/*.css"
"wwwroot/main/site.css"
]
},
{

View file

@ -176,8 +176,18 @@ pre {
background-color: lightgray;
}
[v-cloak] > * { display:none }
[v-cloak]::before { content: "loading…" }
.hide-when-js {
display: block !important;
}
.only-for-js {
display: none !important;
}
[v-cloak] { display:none }
[v-cloak-loading] > * { display:none }
[v-cloak-loading]::before { content: "loading…" }
.cursor-pointer{
cursor: pointer;

View file

@ -18,7 +18,6 @@ function addLoadEvent(func) {
addLoadEvent(function (ev) {
Vue.use(Toasted);
app = new Vue({
el: '#app',
data: function () {
@ -83,6 +82,13 @@ addLoadEvent(function (ev) {
eventAggregator.$emit("pay", amount);
},
copyLink: function (e) {
if (navigator.clipboard) {
e.preventDefault();
navigator.clipboard.writeText(window.location);
e.currentTarget.blur();
}
},
cancelPayment: function (amount) {
this.setLoading(true);
var self = this;
@ -100,9 +106,6 @@ addLoadEvent(function (ev) {
return str;
},
print:function(){
window.print();
},
submitCustomAmountForm : function(e){
if (e) {
e.preventDefault();
@ -115,10 +118,10 @@ addLoadEvent(function (ev) {
}
},
mounted: function () {
this.customAmount = (this.srvModel.amountDue || 0).noExponents();
hubListener.connect();
var self = this;
eventAggregator.$on("invoice-created", function (invoiceId) {
self.setLoading(false);
btcpay.showInvoice(invoiceId);

View file

@ -1,7 +0,0 @@
[v-cloak] > * {
display: none
}
[v-cloak]::before {
content: "loading…"
}