Sticky header updates (#3471)

* Add tag helper for sticky header

Encapsulates some of the CSS and JS required and makes the usage easier.

* Make sticky header span full content area horizontally

* Use sticky header on remaining list views

* Use sticky header on remaining edit and detail views

* Adapt pull payments view to be consistent with other list views

* Fix form markup

* PSBT test fix

* Update header actions

* Remove sticky header tag helper
This commit is contained in:
d11n 2022-02-21 03:05:42 +01:00 committed by GitHub
parent 2d0eedb132
commit 022cd666eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 313 additions and 327 deletions

View file

@ -19,7 +19,7 @@
<form method="post">
<div class="sticky-header-setup"></div>
<header class="sticky-header d-sm-flex align-items-center justify-content-between">
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<div class="d-flex gap-3 mt-3 mt-sm-0">
<button type="submit" class="btn btn-primary order-sm-1" id="SaveSettings">Save</button>
@ -27,13 +27,8 @@
{
<a class="btn btn-secondary" asp-action="ViewCrowdfund" asp-controller="UIAppsPublic" asp-route-appId="@Model.AppId" id="ViewApp" target="app_@Model.AppId">View</a>
}
<a class="btn btn-secondary" asp-action="ListInvoices" asp-controller="UIInvoice" asp-route-storeId="@Model.StoreId" asp-route-searchterm="@Model.SearchTerm">Invoices</a>
</div>
</header>
<script>
const { offsetHeight } = document.querySelector('.sticky-header-setup + .sticky-header');
document.documentElement.style.scrollPaddingTop = `calc(${offsetHeight}px + var(--btcpay-space-m))`;
</script>
</div>
<partial name="_StatusMessage" />
@ -284,7 +279,8 @@
</div>
</form>
<div id="danger-zone">
<div class="d-flex gap-3 mt-3">
<a class="btn btn-secondary" asp-action="ListInvoices" asp-controller="UIInvoice" asp-route-storeId="@Model.StoreId" asp-route-searchterm="@Model.SearchTerm">Invoices</a>
<a id="DeleteApp" class="btn btn-outline-danger" asp-action="DeleteApp" asp-route-appId="@Model.AppId" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The app <strong>@Model.AppName</strong> and its settings will be permanently deleted." data-confirm-input="DELETE">Delete this app</a>
</div>

View file

@ -7,18 +7,13 @@
<form method="post">
<div class="sticky-header-setup"></div>
<header class="sticky-header d-sm-flex align-items-center justify-content-between">
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<div class="d-flex gap-3 mt-3 mt-sm-0">
<button type="submit" class="btn btn-primary order-sm-1" id="SaveSettings">Save</button>
<a class="btn btn-secondary" asp-action="ViewPointOfSale" asp-controller="UIAppsPublic" asp-route-appId="@Model.Id" id="ViewApp" target="app_@Model.AppId">View</a>
<a class="btn btn-secondary" asp-action="ListInvoices" asp-controller="UIInvoice" asp-route-searchterm="@Model.SearchTerm">Invoices</a>
</div>
</header>
<script>
const { offsetHeight } = document.querySelector('.sticky-header-setup + .sticky-header');
document.documentElement.style.scrollPaddingTop = `calc(${offsetHeight}px + var(--btcpay-space-m))`;
</script>
</div>
<partial name="_StatusMessage" />
@ -255,8 +250,8 @@
</div>
</form>
<h3 class="mt-5 mb-4">Other Actions</h3>
<div id="danger-zone">
<div class="d-flex gap-3 mt-3">
<a class="btn btn-secondary" asp-action="ListInvoices" asp-controller="UIInvoice" asp-route-searchterm="@Model.SearchTerm">Invoices</a>
<a id="DeleteApp" class="btn btn-outline-danger" asp-action="DeleteApp" asp-route-appId="@Model.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The app <strong>@Model.AppName</strong> and its settings will be permanently deleted." data-confirm-input="DELETE">Delete this app</a>
</div>

View file

@ -25,13 +25,18 @@
</script>
}
<partial name="_StatusMessage" />
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<form asp-action="CreateInvoice" method="post" id="create-invoice-form">
<div class="sticky-header-setup"></div>
<div class="sticky-header d-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<input type="submit" value="Create" class="btn btn-primary" id="Create" />
</div>
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<form asp-action="CreateInvoice" method="post" id="create-invoice-form">
<partial name="_StatusMessage" />
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
@if (Model.StoreId != null)
{
@ -58,98 +63,95 @@
<input asp-for="Currency" currency-selection class="form-control" />
<span asp-validation-for="Currency" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="OrderId" class="form-label"></label>
<input asp-for="OrderId" class="form-control" />
<span asp-validation-for="OrderId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ItemDesc" class="form-label"></label>
<input asp-for="ItemDesc" class="form-control" />
<span asp-validation-for="ItemDesc" class="text-danger"></span>
</div>
<div class="form-group mb-4">
<label asp-for="SupportedTransactionCurrencies" class="form-label"></label>
@foreach (var item in Model.AvailablePaymentMethods)
{
<div class="form-check mb-2">
<label class="form-check-label">
<input name="SupportedTransactionCurrencies" class="form-check-input" checked="checked" type="checkbox" value="@item.Value">
@item.Text
</label>
</div>
}
<span asp-validation-for="SupportedTransactionCurrencies" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DefaultPaymentMethod" class="form-label"></label>
<select asp-for="DefaultPaymentMethod" asp-items="Model.AvailablePaymentMethods" class="form-select">
<option value="" selected>Use the stores default</option>
</select>
<span asp-validation-for="DefaultPaymentMethod" class="text-danger"></span>
</div>
<h4 class="mt-5 mb-4">Customer Information</h4>
<div class="form-group">
<label asp-for="BuyerEmail" class="form-label"></label>
<input asp-for="BuyerEmail" class="form-control" />
<span asp-validation-for="BuyerEmail" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="RequiresRefundEmail" class="form-label"></label>
<select asp-for="RequiresRefundEmail" asp-items="@Html.GetEnumSelectList<RequiresRefundEmail>()" class="form-select"></select>
<span asp-validation-for="RequiresRefundEmail" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="OrderId" class="form-label"></label>
<input asp-for="OrderId" class="form-control" />
<span asp-validation-for="OrderId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ItemDesc" class="form-label"></label>
<input asp-for="ItemDesc" class="form-control" />
<span asp-validation-for="ItemDesc" class="text-danger"></span>
</div>
<div class="form-group mb-4">
<label asp-for="SupportedTransactionCurrencies" class="form-label"></label>
@foreach (var item in Model.AvailablePaymentMethods)
{
<div class="form-check mb-2">
<label class="form-check-label">
<input name="SupportedTransactionCurrencies" class="form-check-input" checked="checked" type="checkbox" value="@item.Value">
@item.Text
</label>
</div>
}
<span asp-validation-for="SupportedTransactionCurrencies" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DefaultPaymentMethod" class="form-label"></label>
<select asp-for="DefaultPaymentMethod" asp-items="Model.AvailablePaymentMethods" class="form-select">
<option value="" selected>Use the stores default</option>
</select>
<span asp-validation-for="DefaultPaymentMethod" class="text-danger"></span>
</div>
<h4 class="mt-5 mb-4">Customer Information</h4>
<div class="form-group">
<label asp-for="BuyerEmail" class="form-label"></label>
<input asp-for="BuyerEmail" class="form-control" />
<span asp-validation-for="BuyerEmail" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="RequiresRefundEmail" class="form-label"></label>
<select asp-for="RequiresRefundEmail" asp-items="@Html.GetEnumSelectList<RequiresRefundEmail>()" class="form-select"></select>
<span asp-validation-for="RequiresRefundEmail" class="text-danger"></span>
</div>
<h4 class="mt-5 mb-2">Additional Options</h4>
<div class="form-group">
<div class="accordion" id="additional">
<div class="accordion-item">
<h2 class="accordion-header" id="additional-pos-data-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-pos-data" aria-expanded="false" aria-controls="additional-pos-data">
Point Of Sale Data
<vc:icon symbol="caret-down" />
</button>
</h2>
<div id="additional-pos-data" class="accordion-collapse collapse" aria-labelledby="additional-pos-data-header">
<p>Custom data to correlate the invoice with an order. This data can be a simple text, number or JSON object, e.g. <code>{ "orderId": 615, "product": "Pizza" }</code></p>
<div class="form-group">
<label asp-for="PosData" class="form-label"></label>
<input asp-for="PosData" class="form-control" />
<span asp-validation-for="PosData" class="text-danger"></span>
</div>
<h4 class="mt-5 mb-2">Additional Options</h4>
<div class="form-group">
<div class="accordion" id="additional">
<div class="accordion-item">
<h2 class="accordion-header" id="additional-pos-data-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-pos-data" aria-expanded="false" aria-controls="additional-pos-data">
Point Of Sale Data
<vc:icon symbol="caret-down" />
</button>
</h2>
<div id="additional-pos-data" class="accordion-collapse collapse" aria-labelledby="additional-pos-data-header">
<p>Custom data to correlate the invoice with an order. This data can be a simple text, number or JSON object, e.g. <code>{ "orderId": 615, "product": "Pizza" }</code></p>
<div class="form-group">
<label asp-for="PosData" class="form-label"></label>
<input asp-for="PosData" class="form-control" />
<span asp-validation-for="PosData" class="text-danger"></span>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="additional-notifications-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-notifications" aria-expanded="false" aria-controls="additional-notifications">
Invoice Notifications
<vc:icon symbol="caret-down" />
</button>
</h2>
<div id="additional-notifications" class="accordion-collapse collapse" aria-labelledby="additional-notifications-header">
<div class="accordion-body">
<div class="form-group">
<label asp-for="NotificationUrl" class="form-label"></label>
<input asp-for="NotificationUrl" class="form-control" />
<span asp-validation-for="NotificationUrl" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="NotificationEmail" class="form-label"></label>
<input asp-for="NotificationEmail" class="form-control" />
<span asp-validation-for="NotificationEmail" class="text-danger"></span>
<p id="InvoiceEmailHelpBlock" class="form-text text-muted">
Receive updates for this invoice.
</p>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="additional-notifications-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-notifications" aria-expanded="false" aria-controls="additional-notifications">
Invoice Notifications
<vc:icon symbol="caret-down" />
</button>
</h2>
<div id="additional-notifications" class="accordion-collapse collapse" aria-labelledby="additional-notifications-header">
<div class="accordion-body">
<div class="form-group">
<label asp-for="NotificationUrl" class="form-label"></label>
<input asp-for="NotificationUrl" class="form-control" />
<span asp-validation-for="NotificationUrl" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="NotificationEmail" class="form-label"></label>
<input asp-for="NotificationEmail" class="form-control" />
<span asp-validation-for="NotificationEmail" class="text-danger"></span>
<p id="InvoiceEmailHelpBlock" class="form-text text-muted">
Receive updates for this invoice.
</p>
</div>
</div>
</div>
</div>
</div>
<div class="form-group mt-4">
<input type="submit" value="Create" class="btn btn-primary" id="Create" />
</div>
</form>
</div>
</div>
</div>
</div>
</form>

View file

@ -41,42 +41,39 @@
}
<div class="invoice-details">
<partial name="_StatusMessage" />
<div class="row mb-5">
<h2 class="col col-xl-6 mb-4 mb-xl-0">@ViewData["Title"]</h2>
<div class="col col-xl-6 mb-2 mb-xl-0 text-xl-end">
<div class="d-inline-flex">
@if (Model.ShowCheckout)
{
<a asp-action="Checkout" class="invoice-checkout-link btn btn-primary text-nowrap ms-2" asp-route-invoiceId="@Model.Id">
<i class="fa fa-qrcode"></i>
Checkout
</a>
}
@if (Model.CanRefund)
{
<a id="refundlink" class="btn btn-success text-nowrap" asp-action="Refund" asp-route-invoiceId="@Context.GetRouteValue("invoiceId")"><span class="fa fa-undo"></span> Issue Refund</a>
}
else
{
<button href="#" class="btn btn-secondary text-nowrap" data-bs-toggle="tooltip" title="You can only refund an invoice that has been settled. Please wait for the transaction to confirm on the blockchain before attempting to refund it." disabled><span class="fa fa-undo me-1"></span> Issue refund</button>
}
<form class="p-0 ms-3" asp-action="ToggleArchive" asp-route-invoiceId="@Model.Id" method="post">
<button type="submit" class="btn @(Model.Archived ? "btn-warning" : "btn btn-danger")" id="btn-archive-toggle">
@if (Model.Archived)
{
<span class="text-nowrap" data-bs-toggle="tooltip" title="Unarchive this invoice">Unarchive</span>
}
else
{
<span class="text-nowrap" data-bs-toggle="tooltip" title="Archive this invoice so that it does not appear in the invoice list by default"><i class="fa fa-archive me-1"></i> Archive</span>
}
</button>
</form>
</div>
<div class="sticky-header-setup"></div>
<div class="sticky-header d-md-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<div class="d-flex gap-3 mt-3 mt-md-0">
@if (Model.ShowCheckout)
{
<a asp-action="Checkout" class="invoice-checkout-link btn btn-primary text-nowrap" asp-route-invoiceId="@Model.Id">Checkout</a>
}
@if (Model.CanRefund)
{
<a id="refundlink" class="btn btn-success text-nowrap" asp-action="Refund" asp-route-invoiceId="@Context.GetRouteValue("invoiceId")">Issue Refund</a>
}
else
{
<button href="#" class="btn btn-secondary text-nowrap" data-bs-toggle="tooltip" title="You can only refund an invoice that has been settled. Please wait for the transaction to confirm on the blockchain before attempting to refund it." disabled>Issue refund</button>
}
<form asp-action="ToggleArchive" asp-route-invoiceId="@Model.Id" method="post">
<button type="submit" class="btn @(Model.Archived ? "btn-warning" : "btn btn-danger")" id="btn-archive-toggle">
@if (Model.Archived)
{
<span class="text-nowrap" data-bs-toggle="tooltip" title="Unarchive this invoice">Unarchive</span>
}
else
{
<span class="text-nowrap" data-bs-toggle="tooltip" title="Archive this invoice so that it does not appear in the invoice list by default"><i class="fa fa-archive me-1"></i> Archive</span>
}
</button>
</form>
</div>
</div>
<partial name="_StatusMessage" />
<div class="row justify-content-between">
<div class="col-md-5">
<h3 class="mb-3">Invoice Information</h3>

View file

@ -181,9 +181,8 @@
@Html.HiddenFor(a => a.Count)
<partial name="_StatusMessage" />
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<div class="sticky-header-setup"></div>
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">
@ViewData["Title"]
<small>
@ -198,6 +197,8 @@
</a>
</div>
<partial name="_StatusMessage" />
<partial name="InvoiceStatusChangePartial" />
@* Custom Range Modal *@

View file

@ -1,7 +1,7 @@
@inject SignInManager<ApplicationUser> SignInManager
<div class="sticky-header-setup"></div>
<header class="sticky-header mb-l">
<div class="sticky-header mb-l">
<h2 class="mt-1 mb-2 mb-lg-4">Account Settings</h2>
<nav id="SectionNav">
<div class="nav">
@ -14,8 +14,4 @@
<vc:ui-extension-point location="user-nav" model="@Model"/>
</div>
</nav>
</header>
<script>
const { offsetHeight } = document.querySelector('.sticky-header-setup + .sticky-header');
document.documentElement.style.scrollPaddingTop = `calc(${offsetHeight}px + var(--btcpay-space-m))`;
</script>
</div>

View file

@ -15,11 +15,25 @@
<bundle name="wwwroot/bundles/payment-request-admin-bundle.min.js" asp-append-version="true"></bundle>
}
<partial name="_StatusMessage" />
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<form method="post" action="@Url.Action("EditPaymentRequest", "UIPaymentRequest", new { storeId = Model.StoreId, payReqId = Model.Id }, Context.Request.Scheme)">
<div class="sticky-header-setup"></div>
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<div class="d-flex gap-3 mt-3 mt-sm-0">
@if (string.IsNullOrEmpty(Model.Id))
{
<button type="submit" class="btn btn-primary" id="SaveButton">Create</button>
}
else
{
<button type="submit" class="btn btn-primary order-sm-1" id="SaveButton">Save</button>
<a class="btn btn-secondary" target="_blank" asp-action="ViewPaymentRequest" asp-route-payReqId="@Model.Id" id="ViewPaymentRequest">View</a>
}
</div>
</div>
<partial name="_StatusMessage" />
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
@ -110,30 +124,23 @@
</div>
</div>
</div>
<div class="form-group mt-4 d-flex gap-3">
<button type="submit" class="btn btn-primary" id="SaveButton">
@(string.IsNullOrEmpty(Model.Id) ? "Create" : "Save")
</button>
@if (!string.IsNullOrEmpty(Model.Id))
{
<a class="btn btn-secondary" target="_blank" asp-action="ViewPaymentRequest" asp-route-payReqId="@Model.Id" id="ViewPaymentRequest">View</a>
<a class="btn btn-secondary"
target="_blank"
asp-action="ListInvoices"
asp-controller="UIInvoice"
asp-route-searchterm="@($"orderid:{PaymentRequestRepository.GetOrderIdForPaymentRequest(Model.Id)}")">Invoices</a>
<a class="btn btn-secondary" asp-route-payReqId="@Model.Id" asp-action="ClonePaymentRequest" id="ClonePaymentRequest">Clone</a>
@if (!Model.Archived)
{
<a class="btn btn-secondary" data-bs-toggle="tooltip" title="Archive this payment request so that it does not appear in the payment request list by default" asp-controller="UIPaymentRequest" asp-action="TogglePaymentRequestArchival" asp-route-payReqId="@Model.Id" id="ArchivePaymentRequest">Archive</a>
}
else
{
<a class="btn btn-secondary" data-bs-toggle="tooltip" title="Unarchive this payment request" asp-controller="UIPaymentRequest" asp-action="TogglePaymentRequestArchival" asp-route-payReqId="@Model.Id" id="UnarchivePaymentRequest">Unarchive</a>
}
}
</div>
</div>
</div>
</form>
<div class="d-flex gap-3 mt-3">
<a class="btn btn-secondary"
target="_blank"
asp-action="ListInvoices"
asp-controller="UIInvoice"
asp-route-searchterm="@($"orderid:{PaymentRequestRepository.GetOrderIdForPaymentRequest(Model.Id)}")">Invoices</a>
<a class="btn btn-secondary" asp-route-payReqId="@Model.Id" asp-action="ClonePaymentRequest" id="ClonePaymentRequest">Clone</a>
@if (!Model.Archived)
{
<a class="btn btn-secondary" data-bs-toggle="tooltip" title="Archive this payment request so that it does not appear in the payment request list by default" asp-controller="UIPaymentRequest" asp-action="TogglePaymentRequestArchival" asp-route-payReqId="@Model.Id" id="ArchivePaymentRequest">Archive</a>
}
else
{
<a class="btn btn-secondary" data-bs-toggle="tooltip" title="Unarchive this payment request" asp-controller="UIPaymentRequest" asp-action="TogglePaymentRequestArchival" asp-route-payReqId="@Model.Id" id="UnarchivePaymentRequest">Unarchive</a>
}
</div>

View file

@ -5,9 +5,8 @@
ViewData["Title"] = "Payment Requests";
}
<partial name="_StatusMessage" />
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<div class="sticky-header-setup"></div>
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">
@ViewData["Title"]
<small>
@ -22,6 +21,8 @@
</a>
</div>
<partial name="_StatusMessage" />
<div class="row mb-2">
<div class="col col-lg-8 col-xl-6 mr-auto">
<form asp-action="GetPaymentRequests" method="get">

View file

@ -2,7 +2,7 @@
@inject BTCPayServerOptions _btcPayServerOptions
<div class="sticky-header-setup"></div>
<header class="sticky-header mb-l">
<div class="sticky-header mb-l">
<h2 class="mt-1 mb-2 mb-lg-4">Server Settings</h2>
<nav id="SectionNav">
<div class="nav">
@ -21,8 +21,4 @@
<vc:ui-extension-point location="server-nav" model="@Model"/>
</div>
</nav>
</header>
<script>
const { offsetHeight } = document.querySelector('.sticky-header-setup + .sticky-header');
document.documentElement.style.scrollPaddingTop = `calc(${offsetHeight}px + var(--btcpay-space-m))`;
</script>
</div>

View file

@ -14,14 +14,15 @@
<bundle name="wwwroot/bundles/pull-payment-admin-bundle.min.js" asp-append-version="true"></bundle>
}
<partial name="_StatusMessage" />
<form method="post" asp-route-walletId="@Context.GetRouteValue("walletId")" asp-action="NewPullPayment">
<div class="sticky-header-setup"></div>
<div class="sticky-header d-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<input type="submit" value="Create" class="btn btn-primary" id="Create"/>
</div>
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<form
method="post"
asp-route-walletId="@Context.GetRouteValue("walletId")"
asp-action="NewPullPayment">
<partial name="_StatusMessage" />
<div class="row">
<div class="col-md-6">
<div class="form-group">
@ -90,31 +91,28 @@
</div>
</div>
</div>
<div class="accordion-item"> <h2 class="accordion-header" id="additional-custom-css-header">
<div class="accordion-item">
<h2 class="accordion-header" id="additional-lightning-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-lightning" aria-expanded="false" aria-controls="additional-lightning">
Lightning network settings
<vc:icon symbol="caret-down"/>
</button>
</h2>
<div id="additional-lightning" class="accordion-collapse collapse" aria-labelledby="additional-lightning-header">
<div id="additional-lightning" class="accordion-collapse collapse" aria-labelledby="additional-lightning-header">
<div class="accordion-body">
<div class="form-group">
<label asp-for="BOLT11Expiration" class="form-label"></label>
<div class="input-group">
<input asp-for="BOLT11Expiration" class="form-control" style="max-width:10ch;"/>
<span class="input-group-text">days</span>
</div>
<span asp-validation-for="BOLT11Expiration" class="text-danger"></span>
</div>
<label asp-for="BOLT11Expiration" class="form-label"></label>
<div class="input-group">
<input asp-for="BOLT11Expiration" class="form-control" style="max-width:10ch;"/>
<span class="input-group-text">days</span>
</div>
<span asp-validation-for="BOLT11Expiration" class="text-danger"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" id="Create"/>
</div>
</div>
</div>
</form>

View file

@ -1,7 +1,8 @@
@using BTCPayServer.Views.Stores
@using BTCPayServer.Views.Stores
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Client
@using BTCPayServer.Client.Models
@using ExchangeSharp
@model BTCPayServer.Models.WalletViewModels.PullPaymentsModel
@{
ViewData.SetActivePage(StoreNavPages.PullPayments, "Pull Payments", Context.GetStoreData().Id);
@ -35,9 +36,8 @@
</style>
}
<partial name="_StatusMessage" />
<div class="d-flex align-items-center justify-content-between mb-2">
<div class="sticky-header-setup"></div>
<div class="sticky-header d-flex align-items-center justify-content-between">
<h2 class="mb-0">
@ViewData["Title"]
<small>
@ -51,118 +51,116 @@
</a>
</div>
<ul class="nav nav-pills border bg-tile" style="border-radius: 4px;">
@foreach (var state in Enum.GetValues(typeof(PullPaymentState)).Cast<PullPaymentState>())
{
<li class="nav-item py-0">
<partial name="_StatusMessage" />
<nav id="SectionNav" class="mb-3">
<div class="nav">
@foreach (var state in Enum.GetValues(typeof(PullPaymentState)).Cast<PullPaymentState>())
{
<a id="@state-view"
asp-action="PullPayments"
asp-route-storeId="@Context.GetRouteValue("storeId")"
asp-route-pullPaymentState="@state"
class="nav-link me-1 @(state == Model.ActiveState ? "active" : "")" role="tab">@state</a>
</li>
}
</ul>
class="nav-link @(state == Model.ActiveState ? "active" : "")" role="tab">@state</a>
}
</div>
</nav>
@if (Model.PullPayments.Any())
{
<div class="row">
@foreach (var pp in Model.PullPayments)
{
<script id="tooptip_template_@pp.Id" type="text/template">
<span>Awaiting:&nbsp;<span class="float-end">@pp.Progress.Awaiting</span></span>
<br />
<span>Completed:&nbsp;<span class="float-end">@pp.Progress.Completed</span></span>
<br />
<span>Limit:&nbsp;<span class="float-end">@pp.Progress.Limit</span></span>
@if (pp.Progress.ResetIn != null)
{
<br />
<span>Resets in:&nbsp;<span class="float-end">@pp.Progress.ResetIn</span></span>
}
@if (pp.Progress.EndIn != null)
{
<br />
<span>Expires in:&nbsp;<span class="float-end">@pp.Progress.EndIn</span></span>
}
</script>
}
<table class="table table-hover table-responsive-lg">
<thead class="thead-inverse">
<tr>
<th scope="col">
<a
asp-action="PullPayments"
asp-route-sortOrder="@(nextStartDateSortOrder ?? "asc")"
asp-route-pullPaymentState="@Model.ActiveState"
class="text-nowrap"
title="@(nextStartDateSortOrder == "desc" ? sortByAsc : sortByDesc)">
Start
<span class="fa @(sortIconClass)"></span>
</a>
</th>
<th scope="col">Name</th>
<th scope="col">Refunded</th>
<th scope="col" class="text-end" >Actions</th>
</tr>
</thead>
<tbody>
@foreach (var pp in Model.PullPayments)
{
<script id="tooptip_template_@pp.Id" type="text/template">
<span>Awaiting:&nbsp;<span class="float-end">@pp.Progress.Awaiting</span></span>
<br />
<span>Completed:&nbsp;<span class="float-end">@pp.Progress.Completed</span></span>
<br />
<span>Limit:&nbsp;<span class="float-end">@pp.Progress.Limit</span></span>
@if (pp.Progress.ResetIn != null)
{
<br />
<span>Resets in:&nbsp;<span class="float-end">@pp.Progress.ResetIn</span></span>
}
@if (pp.Progress.EndIn != null)
{
<br />
<span>Expires in:&nbsp;<span class="float-end">@pp.Progress.EndIn</span></span>
}
</script>
<tr>
<td>@pp.StartDate.ToBrowserDate()</td>
<td>@pp.Name</td>
<td class="align-middle">
<div class="progress ppProgress" data-pp="@pp.Id" data-bs-toggle="tooltip" data-bs-html="true">
<div class="progress-bar" role="progressbar" aria-valuenow="@pp.Progress.CompletedPercent"
aria-valuemin="0" aria-valuemax="100" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width:@(pp.Progress.CompletedPercent)%;">
</div>
<div class="progress-bar" role="progressbar" aria-valuenow="@pp.Progress.AwaitingPercent"
aria-valuemin="0" aria-valuemax="100" style="background-color:orange; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width:@(pp.Progress.AwaitingPercent)%;">
</div>
</div>
</td>
<td class="text-end">
<a asp-action="ViewPullPayment"
asp-controller="UIPullPayment"
asp-route-pullPaymentId="@pp.Id">
View
</a> -
<a class="pp-payout"
asp-action="Payouts"
asp-route-storeId="@Context.GetRouteValue("storeId")"
asp-route-pullPaymentId="@pp.Id">
Payouts
</a>
@if (!pp.Archived)
{
<span permission="@Policies.CanModifyStoreSettings"> - </span>
<a asp-action="ArchivePullPayment"
permission="@Policies.CanModifyStoreSettings"
asp-route-storeId="@Context.GetRouteValue("storeId")"
asp-route-pullPaymentId="@pp.Id"
data-bs-toggle="modal"
data-bs-target="#ConfirmModal"
data-description="Do you really want to archive the pull payment <strong>@pp.Name</strong>?">
Archive
</a>
}
</td>
</tr>
}
<div class="col-md-12">
<table class="table table-hover table-responsive-lg">
<thead class="thead-inverse">
<tr>
<th scope="col">
<a
asp-action="PullPayments"
asp-route-sortOrder="@(nextStartDateSortOrder ?? "asc")"
asp-route-pullPaymentState="@Model.ActiveState"
class="text-nowrap"
title="@(nextStartDateSortOrder == "desc" ? sortByAsc : sortByDesc)">
Start
<span class="fa @(sortIconClass)"></span>
</a>
</th>
<th scope="col">Name</th>
<th scope="col">Refunded</th>
<th scope="col" class="text-end" >Actions</th>
</tr>
</thead>
<tbody>
@foreach (var pp in Model.PullPayments)
{
<tr>
<td>@pp.StartDate.ToBrowserDate()</td>
<td>@pp.Name</td>
<td class="align-middle">
<div class="progress ppProgress" data-pp="@pp.Id" data-bs-toggle="tooltip" data-bs-html="true">
<div class="progress-bar" role="progressbar" aria-valuenow="@pp.Progress.CompletedPercent"
aria-valuemin="0" aria-valuemax="100" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width:@(pp.Progress.CompletedPercent)%;">
</div>
<div class="progress-bar" role="progressbar" aria-valuenow="@pp.Progress.AwaitingPercent"
aria-valuemin="0" aria-valuemax="100" style="background-color:orange; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width:@(pp.Progress.AwaitingPercent)%;">
</div>
</div>
</td>
<td class="text-end">
<a asp-action="ViewPullPayment"
asp-controller="UIPullPayment"
asp-route-pullPaymentId="@pp.Id">
View
</a> -
<a class="pp-payout"
asp-action="Payouts"
asp-route-storeId="@Context.GetRouteValue("storeId")"
asp-route-pullPaymentId="@pp.Id">
Payouts
</a>
@if (!pp.Archived)
{
<span permission="@Policies.CanModifyStoreSettings"> - </span>
<a asp-action="ArchivePullPayment"
permission="@Policies.CanModifyStoreSettings"
asp-route-storeId="@Context.GetRouteValue("storeId")"
asp-route-pullPaymentId="@pp.Id"
data-bs-toggle="modal"
data-bs-target="#ConfirmModal"
data-description="Do you really want to archive the pull payment <strong>@pp.Name</strong>?">
Archive
</a>
}
</td>
</tr>
}
</tbody>
</table>
</tbody>
</table>
</div>
<vc:pager view-model="Model"/>
</div>
<vc:pager view-model="Model"/>
<partial name="_Confirm" model="@(new ConfirmModel("Archive pull payment", "Do you really want to archive the pull payment?", "Archive"))"/>
@section PageFootContent {
<script>
var ppProgresses = document.getElementsByClassName("ppProgress");
@section PageFootContent {
<script>
const ppProgresses = document.getElementsByClassName("ppProgress");
for (var i = 0; i < ppProgresses.length; i++) {
var pp = ppProgresses[i];
var ppId = pp.getAttribute("data-pp");
@ -170,11 +168,11 @@
pp.setAttribute("title", template.innerHTML);
}
</script>
}
}
}
else
{
<p class="text-secondary mt-3">
There are no pull payments yet.
<p class="text-secondary mt-4">
There are no @Model.ActiveState.ToStringLowerInvariant() pull payments yet.
</p>
}

View file

@ -3,8 +3,9 @@
@{
var storeId = Context.GetStoreData()?.Id;
}
<div class="sticky-header-setup"></div>
<header class="sticky-header mb-l">
<div class="sticky-header mb-l">
<h2 class="mt-1 mb-2 mb-lg-4">Store Settings</h2>
<nav id="SectionNav">
<div class="nav">
@ -18,8 +19,4 @@
<vc:ui-extension-point location="store-nav" model="@Model"/>
</div>
</nav>
</header>
<script>
const { offsetHeight } = document.querySelector('.sticky-header-setup + .sticky-header');
document.documentElement.style.scrollPaddingTop = `calc(${offsetHeight}px + var(--btcpay-space-m))`;
</script>
</div>

View file

@ -6,10 +6,6 @@
}
<div class="sticky-header-setup"></div>
<header class="sticky-header">
<div class="sticky-header">
<vc:wallet-nav wallet-id="wallet"/>
</header>
<script>
const { offsetHeight } = document.querySelector('.sticky-header-setup + .sticky-header');
document.documentElement.style.scrollPaddingTop = `calc(${offsetHeight}px + var(--btcpay-space-m))`;
</script>
</div>

View file

@ -348,8 +348,10 @@
top: 0;
z-index: 1020;
background: var(--btcpay-body-bg);
padding-top: var(--content-padding-top);
padding-bottom: var(--btcpay-space-l);
/* pull it out of the content padding and adjust its inner padding to make up for that space */
margin-left: calc(var(--content-padding-horizontal) * -1);
margin-right: calc(var(--content-padding-horizontal) * -1);
padding: var(--content-padding-top) var(--content-padding-horizontal) var(--btcpay-space-l);
}
.sticky-header #SectionNav {

View file

@ -1,4 +1,8 @@
document.addEventListener("DOMContentLoaded", function () {
// sticky header
const { offsetHeight } = document.querySelector('.sticky-header-setup + .sticky-header');
document.documentElement.style.scrollPaddingTop = `calc(${offsetHeight}px + var(--btcpay-space-m))`;
// initialize timezone offset value if field is present in page
var timezoneOffset = new Date().getTimezoneOffset();
$("#TimezoneOffset").val(timezoneOffset);