mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-01-07 08:04:29 +01:00
Applies default subject and body text on editing to simplify email rule setup. Once the text is edited manually, the defaus aren't applied on switching the rule type. Also documents the placeholders that can be used.
169 lines
8.8 KiB
Plaintext
169 lines
8.8 KiB
Plaintext
@using BTCPayServer.Client.Models
|
|
@model BTCPayServer.Controllers.UIStoresController.StoreEmailRuleViewModel
|
|
|
|
@{
|
|
Layout = "../Shared/_NavLayout.cshtml";
|
|
ViewData.SetActivePage(StoreNavPages.Emails, "Email Rules", Context.GetStoreData().Id);
|
|
}
|
|
|
|
@section PageHeadContent {
|
|
<link href="~/vendor/summernote/summernote-bs5.css" rel="stylesheet" asp-append-version="true" />
|
|
}
|
|
|
|
<form class="row" asp-action="StoreEmails" method="post" asp-route-storeId="@Context.GetStoreData().Id">
|
|
<div class="col-xxl-constrain">
|
|
<div class="d-flex align-items-center justify-content-between mt-n1 mb-3">
|
|
<h3 class="mb-0">@ViewData["Title"]</h3>
|
|
<div class="d-flex gap-3">
|
|
@if (Model.Rules.Any())
|
|
{
|
|
<button class="btn btn-primary" name="command" type="submit" value="save" id="SaveEmailRules">
|
|
Save
|
|
</button>
|
|
}
|
|
<button class="btn btn-primary" name="command" type="submit" value="add" id="CreateEmailRule">
|
|
<span class="fa fa-plus"></span>
|
|
Create
|
|
</button>
|
|
</div>
|
|
</div>
|
|
@if (!ViewContext.ModelState.IsValid)
|
|
{
|
|
<div asp-validation-summary="All" class="text-danger"></div>
|
|
}
|
|
else
|
|
{
|
|
<p class="mb-0">Email rules allow BTCPay Server to send customized emails from your store based on events.</p>
|
|
}
|
|
|
|
@if (Model.Rules.Any())
|
|
{
|
|
<ul class="list-group list-group-flush">
|
|
@for (var index = 0; index < Model.Rules.Count; index++)
|
|
{
|
|
<li class="list-group-item py-4 px-0 email-rule">
|
|
<div class="form-group">
|
|
<div class="d-flex align-items-center justify-content-between gap-3">
|
|
<label asp-for="Rules[index].Trigger" class="form-label" data-required></label>
|
|
<div class="align-items-right">
|
|
<button name="command" type="submit" value="test:@index" class="d-inline-block btn text-info btn-link p-0">
|
|
<span class="fa fa-send"></span> Test this email rule
|
|
</button>
|
|
|
|
<button name="command" type="submit" value="remove:@index" class="d-inline-block btn text-danger btn-link p-0">
|
|
<span class="fa fa-times"></span> Remove this email rule
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<select asp-for="Rules[index].Trigger" asp-items="@Html.GetEnumSelectList<WebhookEventType>()" class="form-select email-rule-trigger" required></select>
|
|
<span asp-validation-for="Rules[index].Trigger" class="text-danger"></span>
|
|
<div class="form-text">Choose what event sends the email.</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label asp-for="Rules[index].To" class="form-label" data-required>Recipients</label>
|
|
<input type="text" asp-for="Rules[index].To" class="form-control email-rule-to" />
|
|
<span asp-validation-for="Rules[index].To" class="text-danger"></span>
|
|
<div class="form-text">Who to send the email to. For multiple emails, separate with a comma.</div>
|
|
</div>
|
|
<div class="form-check mb-4">
|
|
<input asp-for="Rules[index].CustomerEmail" type="checkbox" class="form-check-input email-rule-customer-email" />
|
|
<label asp-for="Rules[index].CustomerEmail" class="form-check-label">Send the email to the buyer, if email was provided to the invoice</label>
|
|
<span asp-validation-for="Rules[index].CustomerEmail" class="text-danger"></span>
|
|
</div>
|
|
<div class="form-group">
|
|
<label asp-for="Rules[index].Subject" class="form-label" data-required></label>
|
|
<input type="text" asp-for="Rules[index].Subject" class="form-control email-rule-subject" />
|
|
<span asp-validation-for="Rules[index].Subject" class="text-danger"></span>
|
|
</div>
|
|
<div class="form-group">
|
|
<label asp-for="Rules[index].Body" class="form-label" data-required></label>
|
|
<textarea asp-for="Rules[index].Body" class="form-control richtext email-rule-body" rows="4"></textarea>
|
|
<span asp-validation-for="Rules[index].Body" class="text-danger"></span>
|
|
<div class="form-text d-flex gap-2">
|
|
<div>Placeholders:</div>
|
|
<div>
|
|
<code>{Invoice.Id}</code>,
|
|
<code>{Invoice.StoreId}</code>,
|
|
<code>{Invoice.Price}</code>,
|
|
<code>{Invoice.Currency}</code>,
|
|
<code>{Invoice.Status}</code>,
|
|
<code>{Invoice.AdditionalStatus}</code>,
|
|
<code>{Invoice.OrderId}</code>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
}
|
|
</ul>
|
|
}
|
|
else
|
|
{
|
|
<p class="text-secondary mt-3">
|
|
There are no rules yet.
|
|
</p>
|
|
}
|
|
</div>
|
|
</form>
|
|
|
|
@section PageFootContent {
|
|
<partial name="_ValidationScriptsPartial" />
|
|
<script src="~/vendor/summernote/summernote-bs5.js" asp-append-version="true"></script>
|
|
<script>
|
|
(function () {
|
|
const templates = {
|
|
InvoiceCreated: {
|
|
subject: 'Invoice {Invoice.Id} created',
|
|
body: 'Invoice {Invoice.Id} (Order Id: {Invoice.OrderId}) created.'
|
|
},
|
|
InvoiceReceivedPayment: {
|
|
subject: 'Invoice {Invoice.Id} received payment',
|
|
body: 'Invoice {Invoice.Id} (Order Id: {Invoice.OrderId}) received payment.'
|
|
},
|
|
InvoiceProcessing: {
|
|
subject: 'Invoice {Invoice.Id} processing',
|
|
body: 'Invoice {Invoice.Id} (Order Id: {Invoice.OrderId}) is processing.'
|
|
},
|
|
InvoiceExpired: {
|
|
subject: 'Invoice {Invoice.Id} expired',
|
|
body: 'Invoice {Invoice.Id} (Order Id: {Invoice.OrderId}) expired.'
|
|
},
|
|
InvoiceSettled: {
|
|
subject: 'Invoice {Invoice.Id} settled',
|
|
body: 'Invoice {Invoice.Id} (Order Id: {Invoice.OrderId}) is settled.'
|
|
},
|
|
InvoiceInvalid: {
|
|
subject: 'Invoice {Invoice.Id} invalid',
|
|
body: 'Invoice {Invoice.Id} (Order Id: {Invoice.OrderId}) invalid.'
|
|
},
|
|
InvoicePaymentSettled: {
|
|
subject: 'Invoice {Invoice.Id} payment settled',
|
|
body: 'Invoice {Invoice.Id} (Order Id: {Invoice.OrderId}) payment settled.'
|
|
},
|
|
};
|
|
const isEmptyOrDefault = (value, type) => {
|
|
const val = value.replace(/<.*?>/gi, '').trim()
|
|
if (!val) return true;
|
|
return Object.values(templates).find(t => t[type] === val) != null;
|
|
}
|
|
const applyDefault = $trigger => {
|
|
const $emailRule = $trigger.closest('.email-rule');
|
|
const $subject = $emailRule.querySelector('.email-rule-subject');
|
|
const $body = $emailRule.querySelector('.email-rule-body');
|
|
const rule = $trigger.querySelector(`option[value='${$trigger.value}']`).innerText;
|
|
const { subject, body } = templates[rule];
|
|
if (isEmptyOrDefault($subject.value, 'subject') && subject) {
|
|
$subject.value = subject;
|
|
}
|
|
if (isEmptyOrDefault($body.value, 'body') && body) {
|
|
$($body).summernote('reset');
|
|
$($body).summernote('insertText', body);
|
|
}
|
|
}
|
|
delegate('change', '.email-rule-trigger', (e) => { applyDefault(e.target); })
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
document.querySelectorAll('.email-rule-trigger').forEach(applyDefault);
|
|
});
|
|
})();
|
|
</script>
|
|
}
|