Email Rules: Add default texts and document placeholders (#5314)

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.
This commit is contained in:
d11n 2023-09-19 03:10:36 +02:00 committed by GitHub
parent 17d1832dad
commit 7873f94848
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 33 deletions

View file

@ -1,27 +0,0 @@
@using Microsoft.AspNetCore.Server.Kestrel.Core
@model BTCPayServer.Models.ServerViewModels.EmailsViewModel
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData.SetActivePage(StoreNavPages.Emails, "Emails", Context.GetStoreData().Id);
}
<div class="row mb-4">
<div class="col-xl-10 col-xxl-constrain">
<div class="d-flex flex-wrap gap-3 align-items-center justify-content-between mt-n1 mb-4">
<h3 class="mb-0">Email Rules</h3>
<a class="btn btn-secondary" asp-action="StoreEmails" asp-controller="UIStores" asp-route-storeId="@Context.GetStoreData().Id" id="ConfigureEmailRules">
Configure
</a>
</div>
<p>
<a asp-action="StoreEmails" asp-controller="UIStores" asp-route-storeId="@Context.GetStoreData().Id">Email rules</a>
allow BTCPay Server to send customized emails from your store based on events.
</p>
</div>
</div>
<partial name="EmailsBody" model="Model" />
@section PageFootContent {
<partial name="_ValidationScriptsPartial" />
}

View file

@ -41,7 +41,7 @@
<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">
<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>
@ -55,30 +55,42 @@
</button>
</div>
</div>
<select asp-for="Rules[index].Trigger" asp-items="@Html.GetEnumSelectList<WebhookEventType>()" class="form-select" required></select>
<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" />
<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" />
<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" />
<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" rows="4"></textarea>
<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>
}
@ -96,4 +108,61 @@
@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>
}