mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-02-17 20:24:28 +01:00
Allowing for POS to be displayed at website root (#853)
* Allowing for POS to be displayed at website root * Switching to asp attributes for form post action * Applying default formatting rules on HTML
This commit is contained in:
committed by
Nicolas Dorier
parent
5a73358bca
commit
de1c2b0150
@@ -91,6 +91,77 @@ namespace BTCPayServer.Controllers
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("/apps/{appId}/pos")]
|
||||
[XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.AllowAll)]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[EnableCors(CorsPolicies.All)]
|
||||
public async Task<IActionResult> ViewPointOfSale(string appId,
|
||||
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal amount,
|
||||
string email,
|
||||
string orderId,
|
||||
string notificationUrl,
|
||||
string redirectUrl,
|
||||
string choiceKey,
|
||||
string posData = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var app = await _AppService.GetApp(appId, AppType.PointOfSale);
|
||||
if (string.IsNullOrEmpty(choiceKey) && amount <= 0)
|
||||
{
|
||||
return RedirectToAction(nameof(ViewPointOfSale), new { appId = appId });
|
||||
}
|
||||
if (app == null)
|
||||
return NotFound();
|
||||
var settings = app.GetSettings<PointOfSaleSettings>();
|
||||
if (string.IsNullOrEmpty(choiceKey) && !settings.ShowCustomAmount && !settings.EnableShoppingCart)
|
||||
{
|
||||
return RedirectToAction(nameof(ViewPointOfSale), new { appId = appId });
|
||||
}
|
||||
string title = null;
|
||||
var price = 0.0m;
|
||||
ViewPointOfSaleViewModel.Item choice = null;
|
||||
if (!string.IsNullOrEmpty(choiceKey))
|
||||
{
|
||||
var choices = _AppService.Parse(settings.Template, settings.Currency);
|
||||
choice = choices.FirstOrDefault(c => c.Id == choiceKey);
|
||||
if (choice == null)
|
||||
return NotFound();
|
||||
title = choice.Title;
|
||||
price = choice.Price.Value;
|
||||
if (amount > price)
|
||||
price = amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!settings.ShowCustomAmount && !settings.EnableShoppingCart)
|
||||
return NotFound();
|
||||
price = amount;
|
||||
title = settings.Title;
|
||||
}
|
||||
var store = await _AppService.GetStore(app);
|
||||
store.AdditionalClaims.Add(new Claim(Policies.CanCreateInvoice.Key, store.Id));
|
||||
var invoice = await _InvoiceController.CreateInvoiceCore(new CreateInvoiceRequest()
|
||||
{
|
||||
ItemCode = choice?.Id,
|
||||
ItemDesc = title,
|
||||
Currency = settings.Currency,
|
||||
Price = price,
|
||||
BuyerEmail = email,
|
||||
OrderId = orderId,
|
||||
NotificationURL =
|
||||
string.IsNullOrEmpty(notificationUrl) ? settings.NotificationUrl : notificationUrl,
|
||||
NotificationEmail = settings.NotificationEmail,
|
||||
RedirectURL = redirectUrl ?? Request.GetDisplayUrl(),
|
||||
FullNotifications = true,
|
||||
ExtendedNotifications = true,
|
||||
PosData = string.IsNullOrEmpty(posData) ? null : posData,
|
||||
RedirectAutomatically = settings.RedirectAutomatically,
|
||||
}, store, HttpContext.Request.GetAbsoluteRoot(),
|
||||
new List<string>() { AppService.GetAppInternalTag(appId) },
|
||||
cancellationToken);
|
||||
return RedirectToAction(nameof(InvoiceController.Checkout), "Invoice", new { invoiceId = invoice.Data.Id });
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[Route("/apps/{appId}/crowdfund")]
|
||||
@@ -215,77 +286,6 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("/apps/{appId}/pos")]
|
||||
[XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.AllowAll)]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[EnableCors(CorsPolicies.All)]
|
||||
public async Task<IActionResult> ViewPointOfSale(string appId,
|
||||
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal amount,
|
||||
string email,
|
||||
string orderId,
|
||||
string notificationUrl,
|
||||
string redirectUrl,
|
||||
string choiceKey,
|
||||
string posData = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var app = await _AppService.GetApp(appId, AppType.PointOfSale);
|
||||
if (string.IsNullOrEmpty(choiceKey) && amount <= 0)
|
||||
{
|
||||
return RedirectToAction(nameof(ViewPointOfSale), new { appId = appId });
|
||||
}
|
||||
if (app == null)
|
||||
return NotFound();
|
||||
var settings = app.GetSettings<PointOfSaleSettings>();
|
||||
if (string.IsNullOrEmpty(choiceKey) && !settings.ShowCustomAmount && !settings.EnableShoppingCart)
|
||||
{
|
||||
return RedirectToAction(nameof(ViewPointOfSale), new { appId = appId });
|
||||
}
|
||||
string title = null;
|
||||
var price = 0.0m;
|
||||
ViewPointOfSaleViewModel.Item choice = null;
|
||||
if (!string.IsNullOrEmpty(choiceKey))
|
||||
{
|
||||
var choices = _AppService.Parse(settings.Template, settings.Currency);
|
||||
choice = choices.FirstOrDefault(c => c.Id == choiceKey);
|
||||
if (choice == null)
|
||||
return NotFound();
|
||||
title = choice.Title;
|
||||
price = choice.Price.Value;
|
||||
if (amount > price)
|
||||
price = amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!settings.ShowCustomAmount && !settings.EnableShoppingCart)
|
||||
return NotFound();
|
||||
price = amount;
|
||||
title = settings.Title;
|
||||
}
|
||||
var store = await _AppService.GetStore(app);
|
||||
store.AdditionalClaims.Add(new Claim(Policies.CanCreateInvoice.Key, store.Id));
|
||||
var invoice = await _InvoiceController.CreateInvoiceCore(new CreateInvoiceRequest()
|
||||
{
|
||||
ItemCode = choice?.Id,
|
||||
ItemDesc = title,
|
||||
Currency = settings.Currency,
|
||||
Price = price,
|
||||
BuyerEmail = email,
|
||||
OrderId = orderId,
|
||||
NotificationURL =
|
||||
string.IsNullOrEmpty(notificationUrl) ? settings.NotificationUrl : notificationUrl,
|
||||
NotificationEmail = settings.NotificationEmail,
|
||||
RedirectURL = redirectUrl ?? Request.GetDisplayUrl(),
|
||||
FullNotifications = true,
|
||||
ExtendedNotifications = true,
|
||||
PosData = string.IsNullOrEmpty(posData) ? null : posData,
|
||||
RedirectAutomatically = settings.RedirectAutomatically,
|
||||
}, store, HttpContext.Request.GetAbsoluteRoot(),
|
||||
new List<string>() { AppService.GetAppInternalTag(appId) },
|
||||
cancellationToken);
|
||||
return RedirectToAction(nameof(InvoiceController.Checkout), "Invoice", new { invoiceId = invoice.Data.Id });
|
||||
}
|
||||
|
||||
|
||||
private string GetUserId()
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace BTCPayServer.Controllers
|
||||
HttpClientFactory = httpClientFactory;
|
||||
_cachedServerSettings = cachedServerSettings;
|
||||
}
|
||||
|
||||
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
if (_cachedServerSettings.RootAppType is Services.Apps.AppType.Crowdfund)
|
||||
@@ -40,6 +40,20 @@ namespace BTCPayServer.Controllers
|
||||
return res; // return
|
||||
}
|
||||
}
|
||||
else if (_cachedServerSettings.RootAppType is Services.Apps.AppType.PointOfSale)
|
||||
{
|
||||
var serviceProvider = HttpContext.RequestServices;
|
||||
var controller = (AppsPublicController)serviceProvider.GetService(typeof(AppsPublicController));
|
||||
controller.Url = Url;
|
||||
controller.ControllerContext = ControllerContext;
|
||||
var res = await controller.ViewPointOfSale(_cachedServerSettings.RootAppId) as ViewResult;
|
||||
if (res != null)
|
||||
{
|
||||
res.ViewName = "/Views/AppsPublic/ViewPointOfSale.cshtml";
|
||||
return res; // return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return View("Home");
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<html class="h-100">
|
||||
<head>
|
||||
<title>@Model.Title</title>
|
||||
<meta charset="utf-8"/>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<link rel="apple-touch-icon" href="~/img/icons/icon-512x512.png">
|
||||
@@ -20,12 +20,12 @@
|
||||
|
||||
<link rel="manifest" href="~/manifest.json">
|
||||
|
||||
<link href="@this.Context.Request.GetRelativePathOrAbsolute(themeManager.BootstrapUri)" rel="stylesheet"/>
|
||||
<link href="@this.Context.Request.GetRelativePathOrAbsolute(themeManager.BootstrapUri)" rel="stylesheet" />
|
||||
@if (Model.CustomCSSLink != null)
|
||||
{
|
||||
<link href="@Model.CustomCSSLink" rel="stylesheet"/>
|
||||
<link href="@Model.CustomCSSLink" rel="stylesheet" />
|
||||
}
|
||||
<link href="~/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet"/>
|
||||
<link href="~/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" />
|
||||
|
||||
@if (Model.EnableShoppingCart)
|
||||
{
|
||||
@@ -33,7 +33,7 @@
|
||||
<script type="text/javascript">
|
||||
var srvModel = @Html.Raw(Json.Serialize(Model));
|
||||
</script>
|
||||
<bundle name="wwwroot/bundles/cart-bundle.min.js"/>
|
||||
<bundle name="wwwroot/bundles/cart-bundle.min.js" />
|
||||
}
|
||||
<style>
|
||||
.card-deck {
|
||||
@@ -42,367 +42,370 @@
|
||||
grid-gap: .5rem;
|
||||
}
|
||||
|
||||
.card-deck .card:only-of-type {
|
||||
max-width: 320px;
|
||||
margin: auto;
|
||||
}
|
||||
.card-deck .card:only-of-type {
|
||||
max-width: 320px;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="h-100">
|
||||
<script id="template-cart-item" type="text/template">
|
||||
<tr data-id="{id}">
|
||||
{image}
|
||||
<td class="align-middle pr-0 pl-2"><b>{title}</b></td>
|
||||
<td class="align-middle px-0" align="right">
|
||||
<a class="js-cart-item-remove btn btn-link" href="#"><i class="fa fa-trash text-muted"></i></a>
|
||||
</td>
|
||||
<td class="align-middle px-0" align="right">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<a class="js-cart-item-minus btn btn-link px-2" href="#"><i class="fa fa-minus-circle fa-fw text-danger"></i></a>
|
||||
</div>
|
||||
<input class="js-cart-item-count form-control form-control-sm pull-left" type="text"name="count" placeholder="Qty" value="{count}" data-prev="{count}">
|
||||
<div class="input-group-append"><a class="js-cart-item-plus btn btn-link px-2" href="#">
|
||||
<i class="fa fa-plus-circle fa-fw text-success"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle" align="right">{price}</td>
|
||||
</tr>
|
||||
</script>
|
||||
|
||||
<script id="template-cart-item-image" type="text/template">
|
||||
<td class="align-middle pr-0" width="1%"><img src="{image}" width="50"></td>
|
||||
</script>
|
||||
|
||||
<script id="template-cart-custom-amount" type="text/template">
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-shopping-cart fa-fw"></i></span>
|
||||
</div>
|
||||
<input class="js-cart-custom-amount form-control" type="number" min="0" step="@Model.Step" name="amount" placeholder="Pay what you want">
|
||||
<div class="input-group-append">
|
||||
<a class="js-cart-custom-amount-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
|
||||
<script id="template-cart-extra" type="text/template">
|
||||
<tr>
|
||||
<td colspan="5" class="border-0 pb-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-shopping-cart fa-fw"></i></span>
|
||||
</div>
|
||||
<input class="js-cart-custom-amount form-control" type="number" min="0" step="@Model.Step" name="amount" value="{customAmount}" placeholder="Pay what you want">
|
||||
<div class="input-group-append">
|
||||
<a class="js-cart-custom-amount-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@if (Model.ShowDiscount)
|
||||
{
|
||||
<tr>
|
||||
<td colspan="5" class="border-top-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-percent fa-fw"></i></span>
|
||||
</div>
|
||||
<input class="js-cart-discount form-control" type="number" min="0" step="@Model.Step" value="{discount}" name="discount" placeholder="Discount in %">
|
||||
<div class="input-group-append">
|
||||
<a class="js-cart-discount-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="template-cart-tip" type="text/template">
|
||||
@if (Model.EnableTips)
|
||||
{
|
||||
<tr class="h5">
|
||||
<td colspan="5" class="border-top-0 pt-4">@Model.CustomTipText</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5" class="border-0">
|
||||
<div class="input-group mb-2">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-money fa-fw"></i></span>
|
||||
</div>
|
||||
<input class="js-cart-tip form-control" type="number" min="0" step="@Model.Step" value="{tip}" name="tip" placeholder="Tip in @(Model.CurrencyInfo.CurrencySymbol != null ? Model.CurrencyInfo.CurrencySymbol : Model.CurrencyCode)">
|
||||
<div class="input-group-append">
|
||||
<a class="js-cart-tip-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1">
|
||||
@if (CustomTipPercentages != null && CustomTipPercentages.Length > 0)
|
||||
{
|
||||
@for (int i = 0; i < CustomTipPercentages.Length; i++)
|
||||
{
|
||||
var percentage = CustomTipPercentages[i];
|
||||
<div class="col">
|
||||
<a class="js-cart-tip-btn btn btn-light btn-block border mb-2" href="#" data-tip="@percentage">@percentage%</a>
|
||||
<script id="template-cart-item" type="text/template">
|
||||
<tr data-id="{id}">
|
||||
{image}
|
||||
<td class="align-middle pr-0 pl-2"><b>{title}</b></td>
|
||||
<td class="align-middle px-0" align="right">
|
||||
<a class="js-cart-item-remove btn btn-link" href="#"><i class="fa fa-trash text-muted"></i></a>
|
||||
</td>
|
||||
<td class="align-middle px-0" align="right">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<a class="js-cart-item-minus btn btn-link px-2" href="#"><i class="fa fa-minus-circle fa-fw text-danger"></i></a>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>}
|
||||
</script>
|
||||
|
||||
<script id="template-cart-total" type="text/template">
|
||||
<tr class="h4 table-light">
|
||||
<td colspan="1" class="pb-4">Total</td>
|
||||
<td colspan="4" align="right" class="pb-4">
|
||||
<span class="js-cart-total">{total}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
|
||||
@if (Model.EnableShoppingCart)
|
||||
{
|
||||
<div id="cartModal" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white border-0">
|
||||
<h5 class="modal-title">Confirmation</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">
|
||||
<i class="fa fa-times fa-fw"></i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body p-0">
|
||||
<table id="js-cart-summary" class="table m-0">
|
||||
<tbody class="my-3">
|
||||
<tr class="h5">
|
||||
<td colspan="2" class="border-top-0">Summary</td>
|
||||
</tr>
|
||||
<tr class="h6">
|
||||
<td class="border-0 pb-0">Total products</td>
|
||||
<td align="right" class="border-0 pb-0">
|
||||
<span class="js-cart-summary-products text-nowrap"></span>
|
||||
</td>
|
||||
</tr>
|
||||
@if (Model.ShowDiscount)
|
||||
{
|
||||
<tr class="h6">
|
||||
<td class="border-0 pb-y">Discount</td>
|
||||
<td align="right" class="border-0 pb-y">
|
||||
<span class="js-cart-summary-discount text-nowrap"></span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.EnableTips)
|
||||
{
|
||||
<tr class="h6">
|
||||
<td class="border-top-0 pt-0">Tip</td>
|
||||
<td align="right" class="border-top-0 pt-0">
|
||||
<span class="js-cart-summary-tip text-nowrap"></span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
<tr class="h3 table-light">
|
||||
<td>Total</td>
|
||||
<td align="right">
|
||||
<span class="js-cart-summary-total text-nowrap"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<form method="post" asp-antiforgery="false" data-buy>
|
||||
<input id="js-cart-amount" class="form-control" type="hidden" name="amount">
|
||||
<input id="js-cart-posdata" class="form-control" type="hidden" name="posdata">
|
||||
<button id="js-cart-pay" class="btn btn-primary btn-lg" type="submit">
|
||||
<b>@Model.CustomButtonText</b>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wrapper">
|
||||
<!-- Page Content -->
|
||||
<div id="content">
|
||||
<div class="p-3">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 col-lg-3 order-sm-last text-right mb-2">
|
||||
<a class="js-cart btn btn-warning text-white text-right" href="#">
|
||||
<i class="fa fa-shopping-basket"></i>
|
||||
<span class="badge badge-light badge-pill">
|
||||
<span id="js-cart-items">0</span>
|
||||
</span>
|
||||
<input class="js-cart-item-count form-control form-control-sm pull-left" type="text" name="count" placeholder="Qty" value="{count}" data-prev="{count}">
|
||||
<div class="input-group-append">
|
||||
<a class="js-cart-item-plus btn btn-link px-2" href="#">
|
||||
<i class="fa fa-plus-circle fa-fw text-success"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-8 col-lg-9 mb-2">
|
||||
<div class="input-group mb-2">
|
||||
<input type="text" class="js-search form-control" placeholder="Find product">
|
||||
<a class="js-search-reset btn btn-link text-black" href="#" style="position: absolute; right: 0px; z-index: 1049; display: none;">
|
||||
<i class="fa fa-times-circle fa-lg"></i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle" align="right">{price}</td>
|
||||
</tr>
|
||||
</script>
|
||||
|
||||
<script id="template-cart-item-image" type="text/template">
|
||||
<td class="align-middle pr-0" width="1%"><img src="{image}" width="50"></td>
|
||||
</script>
|
||||
|
||||
<script id="template-cart-custom-amount" type="text/template">
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-shopping-cart fa-fw"></i></span>
|
||||
</div>
|
||||
<input class="js-cart-custom-amount form-control" type="number" min="0" step="@Model.Step" name="amount" placeholder="Pay what you want">
|
||||
<div class="input-group-append">
|
||||
<a class="js-cart-custom-amount-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
|
||||
<script id="template-cart-extra" type="text/template">
|
||||
<tr>
|
||||
<td colspan="5" class="border-0 pb-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-shopping-cart fa-fw"></i></span>
|
||||
</div>
|
||||
<input class="js-cart-custom-amount form-control" type="number" min="0" step="@Model.Step" name="amount" value="{customAmount}" placeholder="Pay what you want">
|
||||
<div class="input-group-append">
|
||||
<a class="js-cart-custom-amount-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@if (Model.ShowDiscount)
|
||||
{
|
||||
<tr>
|
||||
<td colspan="5" class="border-top-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-percent fa-fw"></i></span>
|
||||
</div>
|
||||
<input class="js-cart-discount form-control" type="number" min="0" step="@Model.Step" value="{discount}" name="discount" placeholder="Discount in %">
|
||||
<div class="input-group-append">
|
||||
<a class="js-cart-discount-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="template-cart-tip" type="text/template">
|
||||
@if (Model.EnableTips)
|
||||
{
|
||||
<tr class="h5">
|
||||
<td colspan="5" class="border-top-0 pt-4">@Model.CustomTipText</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5" class="border-0">
|
||||
<div class="input-group mb-2">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-money fa-fw"></i></span>
|
||||
</div>
|
||||
<input class="js-cart-tip form-control" type="number" min="0" step="@Model.Step" value="{tip}" name="tip" placeholder="Tip in @(Model.CurrencyInfo.CurrencySymbol != null ? Model.CurrencyInfo.CurrencySymbol : Model.CurrencyCode)">
|
||||
<div class="input-group-append">
|
||||
<a class="js-cart-tip-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1">
|
||||
@if (CustomTipPercentages != null && CustomTipPercentages.Length > 0)
|
||||
{
|
||||
@for (int i = 0; i < CustomTipPercentages.Length; i++)
|
||||
{
|
||||
var percentage = CustomTipPercentages[i];
|
||||
<div class="col">
|
||||
<a class="js-cart-tip-btn btn btn-light btn-block border mb-2" href="#" data-tip="@percentage">@percentage%</a>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>}
|
||||
</script>
|
||||
|
||||
<script id="template-cart-total" type="text/template">
|
||||
<tr class="h4 table-light">
|
||||
<td colspan="1" class="pb-4">Total</td>
|
||||
<td colspan="4" align="right" class="pb-4">
|
||||
<span class="js-cart-total">{total}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
|
||||
@if (Model.EnableShoppingCart)
|
||||
{
|
||||
<div id="cartModal" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white border-0">
|
||||
<h5 class="modal-title">Confirmation</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">
|
||||
<i class="fa fa-times fa-fw"></i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body p-0">
|
||||
<table id="js-cart-summary" class="table m-0">
|
||||
<tbody class="my-3">
|
||||
<tr class="h5">
|
||||
<td colspan="2" class="border-top-0">Summary</td>
|
||||
</tr>
|
||||
<tr class="h6">
|
||||
<td class="border-0 pb-0">Total products</td>
|
||||
<td align="right" class="border-0 pb-0">
|
||||
<span class="js-cart-summary-products text-nowrap"></span>
|
||||
</td>
|
||||
</tr>
|
||||
@if (Model.ShowDiscount)
|
||||
{
|
||||
<tr class="h6">
|
||||
<td class="border-0 pb-y">Discount</td>
|
||||
<td align="right" class="border-0 pb-y">
|
||||
<span class="js-cart-summary-discount text-nowrap"></span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.EnableTips)
|
||||
{
|
||||
<tr class="h6">
|
||||
<td class="border-top-0 pt-0">Tip</td>
|
||||
<td align="right" class="border-top-0 pt-0">
|
||||
<span class="js-cart-summary-tip text-nowrap"></span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
<tr class="h3 table-light">
|
||||
<td>Total</td>
|
||||
<td align="right">
|
||||
<span class="js-cart-summary-total text-nowrap"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<form method="post" asp-controller="AppsPublic" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false" data-buy>
|
||||
<input id="js-cart-amount" class="form-control" type="hidden" name="amount">
|
||||
<input id="js-cart-posdata" class="form-control" type="hidden" name="posdata">
|
||||
<button id="js-cart-pay" class="btn btn-primary btn-lg" type="submit">
|
||||
<b>@Model.CustomButtonText</b>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wrapper">
|
||||
<!-- Page Content -->
|
||||
<div id="content">
|
||||
<div class="p-3">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 col-lg-3 order-sm-last text-right mb-2">
|
||||
<a class="js-cart btn btn-warning text-white text-right" href="#">
|
||||
<i class="fa fa-shopping-basket"></i>
|
||||
<span class="badge badge-light badge-pill">
|
||||
<span id="js-cart-items">0</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-8 col-lg-9 mb-2">
|
||||
<div class="input-group mb-2">
|
||||
<input type="text" class="js-search form-control" placeholder="Find product">
|
||||
<a class="js-search-reset btn btn-link text-black" href="#" style="position: absolute; right: 0px; z-index: 1049; display: none;">
|
||||
<i class="fa fa-times-circle fa-lg"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="js-pos-list" class="text-center mx-auto px-4">
|
||||
<div class="row card-deck my-3 mx-auto">
|
||||
|
||||
@for (var index = 0; index < Model.Items.Length; index++)
|
||||
{
|
||||
var item = Model.Items[index];
|
||||
var image = item.Image;
|
||||
var description = item.Description;
|
||||
|
||||
<div class="js-add-cart card my-2 card-wrapper" data-id="@index">
|
||||
@if (!String.IsNullOrWhiteSpace(image))
|
||||
{
|
||||
@:<img class="card-img-top" src="@image" alt="Card image cap">
|
||||
}
|
||||
<div class="card-body p-3">
|
||||
<h6 class="card-title mb-0">@item.Title</h6>
|
||||
@if (!String.IsNullOrWhiteSpace(description))
|
||||
{
|
||||
<p class="card-text">@description</p>
|
||||
}
|
||||
</div>
|
||||
<div class="card-footer pt-0 bg-transparent border-0">
|
||||
|
||||
<span class="text-muted small">@String.Format(Model.ButtonText, @item.Price.Formatted)</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="js-pos-list" class="text-center mx-auto px-4">
|
||||
<div class="row card-deck my-3 mx-auto">
|
||||
<!-- Sidebar -->
|
||||
<nav id="sidebar" class="bg-dark">
|
||||
<div class="bg-warning p-3 clearfix">
|
||||
<h3 class="text-white m-0 pull-left">Cart</h3>
|
||||
<a class="js-cart btn btn-sm bg-white text-black pull-right ml-5" href="#">
|
||||
<i class="fa fa-times fa-lg"></i>
|
||||
</a>
|
||||
<a class="js-cart-destroy btn btn-sm bg-white text-danger pull-right" href="#" style="display: none;">Empty cart <i class="fa fa-trash fa-fw fa-lg"></i></a>
|
||||
</div>
|
||||
|
||||
@for (var index = 0; index < Model.Items.Length; index++)
|
||||
<table id="js-cart-list" class="table table-responsive bg-light mt-0 mb-0">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th colspan="3" width="55%">Product</th>
|
||||
<th class="text-center" width="20%">
|
||||
<div style="width: 84px">Quantity</div>
|
||||
</th>
|
||||
<th class="text-right" width="25%">
|
||||
<div style="min-width: 50px">Price</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
|
||||
<table id="js-cart-extra" class="table bg-light mt-0 mb-0">
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
|
||||
<button id="js-cart-confirm" data-toggle="modal" data-target="#cartModal" class="btn btn-primary btn-lg btn-block mb-3 p-3" disabled="disabled" type="submit">
|
||||
<b>Confirm</b>
|
||||
</button>
|
||||
|
||||
<div class="text-center mb-5 pb-5">
|
||||
<img src="~/img/logo-white.png" height="40">
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="container d-flex h-100">
|
||||
<div class="justify-content-center align-self-center text-center mx-auto px-2 py-3 w-100" style="margin: auto;">
|
||||
<h1 class="mb-4">@Model.Title</h1>
|
||||
|
||||
<div class="row card-deck my-3 mx-auto">
|
||||
@for (int x = 0; x < Model.Items.Length; x++)
|
||||
{
|
||||
var item = Model.Items[index];
|
||||
var image = item.Image;
|
||||
var description = item.Description;
|
||||
var item = Model.Items[x];
|
||||
|
||||
<div class="js-add-cart card my-2 card-wrapper" data-id="@index">
|
||||
@if (!String.IsNullOrWhiteSpace(image))
|
||||
<div class="card my-2" data-id="@x">
|
||||
@if (!String.IsNullOrWhiteSpace(item.Image))
|
||||
{
|
||||
@:<img class="card-img-top" src="@image" alt="Card image cap">
|
||||
<img class="card-img-top" src="@item.Image" alt="Card image cap">
|
||||
}
|
||||
<div class="card-body p-3">
|
||||
<h6 class="card-title mb-0">@item.Title</h6>
|
||||
@if (!String.IsNullOrWhiteSpace(description))
|
||||
<div class="card-body pb-0">
|
||||
<h5 class="card-title">@item.Title</h5>
|
||||
@if (!String.IsNullOrWhiteSpace(item.Description))
|
||||
{
|
||||
<p class="card-text">@description</p>
|
||||
<p class="card-text">@item.Description</p>
|
||||
}
|
||||
|
||||
</div>
|
||||
<div class="card-footer bg-transparent border-0">
|
||||
@if (item.Custom)
|
||||
{
|
||||
<form method="post" asp-controller="AppsPublic" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false" data-buy>
|
||||
<input type="hidden" name="choicekey" value="@item.Id" />
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">@Model.CurrencySymbol</span>
|
||||
</div>
|
||||
<input class="form-control" type="number" min="@item.Price.Value" step="@Model.Step" name="amount"
|
||||
value="@item.Price.Value" placeholder="Amount">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary" type="submit">@Model.CustomButtonText</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form method="post" asp-controller="AppsPublic" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false">
|
||||
<button type="submit" name="choiceKey" class="js-add-cart btn btn-primary" value="@item.Id">
|
||||
@String.Format(Model.ButtonText, @item.Price.Formatted)
|
||||
</button>
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
<div class="card-footer pt-0 bg-transparent border-0">
|
||||
|
||||
<span class="text-muted small">@String.Format(Model.ButtonText, @item.Price.Formatted)</span>
|
||||
</div>
|
||||
}
|
||||
@if (Model.ShowCustomAmount)
|
||||
{
|
||||
<div class="card my-2">
|
||||
<div class="card-body my-auto pb-0">
|
||||
<h5 class="card-title">Custom Amount</h5>
|
||||
<p class="card-text">Create invoice to pay custom amount</p>
|
||||
|
||||
</div>
|
||||
<div class="card-footer bg-transparent border-0">
|
||||
<form method="post" asp-controller="AppsPublic" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false" data-buy>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">@Model.CurrencySymbol</span>
|
||||
</div>
|
||||
<input class="form-control" type="number" min="0" step="@Model.Step" name="amount" placeholder="Amount">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary" type="submit">@Model.CustomButtonText</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<nav id="sidebar" class="bg-dark">
|
||||
<div class="bg-warning p-3 clearfix">
|
||||
<h3 class="text-white m-0 pull-left">Cart</h3>
|
||||
<a class="js-cart btn btn-sm bg-white text-black pull-right ml-5" href="#">
|
||||
<i class="fa fa-times fa-lg"></i>
|
||||
</a>
|
||||
<a class="js-cart-destroy btn btn-sm bg-white text-danger pull-right" href="#" style="display: none;">Empty cart <i class="fa fa-trash fa-fw fa-lg"></i></a>
|
||||
</div>
|
||||
|
||||
<table id="js-cart-list" class="table table-responsive bg-light mt-0 mb-0">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th colspan="3" width="55%">Product</th>
|
||||
<th class="text-center" width="20%">
|
||||
<div style="width: 84px">Quantity</div>
|
||||
</th>
|
||||
<th class="text-right" width="25%">
|
||||
<div style="min-width: 50px">Price</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
|
||||
<table id="js-cart-extra" class="table bg-light mt-0 mb-0">
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
|
||||
<button id="js-cart-confirm" data-toggle="modal" data-target="#cartModal" class="btn btn-primary btn-lg btn-block mb-3 p-3" disabled="disabled" type="submit">
|
||||
<b>Confirm</b>
|
||||
</button>
|
||||
|
||||
<div class="text-center mb-5 pb-5">
|
||||
<img src="~/img/logo-white.png" height="40">
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="container d-flex h-100">
|
||||
<div class="justify-content-center align-self-center text-center mx-auto px-2 py-3 w-100" style="margin: auto;">
|
||||
<h1 class="mb-4">@Model.Title</h1>
|
||||
|
||||
<div class="row card-deck my-3 mx-auto">
|
||||
@for (int x = 0; x < Model.Items.Length; x++)
|
||||
{
|
||||
var item = Model.Items[x];
|
||||
|
||||
<div class="card my-2" data-id="@x">
|
||||
@if (!String.IsNullOrWhiteSpace(item.Image))
|
||||
{
|
||||
<img class="card-img-top" src="@item.Image" alt="Card image cap">
|
||||
}
|
||||
<div class="card-body pb-0">
|
||||
<h5 class="card-title">@item.Title</h5>
|
||||
@if (!String.IsNullOrWhiteSpace(item.Description))
|
||||
{
|
||||
<p class="card-text">@item.Description</p>
|
||||
}
|
||||
|
||||
</div>
|
||||
<div class="card-footer bg-transparent border-0">
|
||||
@if (item.Custom)
|
||||
{
|
||||
<form method="post" asp-antiforgery="false" data-buy>
|
||||
<input type="hidden" name="choicekey" value="@item.Id"/>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">@Model.CurrencySymbol</span>
|
||||
</div>
|
||||
<input class="form-control" type="number" min="@item.Price.Value" step="@Model.Step" name="amount"
|
||||
value="@item.Price.Value" placeholder="Amount">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary" type="submit">@Model.CustomButtonText</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form method="post" asp-antiforgery="false">
|
||||
<button type="submit" name="choiceKey" class="js-add-cart btn btn-primary" value="@item.Id">
|
||||
@String.Format(Model.ButtonText, @item.Price.Formatted)</button>
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (Model.ShowCustomAmount)
|
||||
{
|
||||
<div class="card my-2">
|
||||
<div class="card-body my-auto pb-0">
|
||||
<h5 class="card-title">Custom Amount</h5>
|
||||
<p class="card-text">Create invoice to pay custom amount</p>
|
||||
|
||||
</div>
|
||||
<div class="card-footer bg-transparent border-0">
|
||||
<form method="post" asp-antiforgery="false" data-buy>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">@Model.CurrencySymbol</span>
|
||||
</div>
|
||||
<input class="form-control" type="number" min="0" step="@Model.Step" name="amount" placeholder="Amount">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary" type="submit">@Model.CustomButtonText</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user