btcpayserver/BTCPayServer/Views/UIStores/StoreEmails.cshtml
d11n a962e60de9
More Translations (#6318)
* Store selector

* Footer

* Notifications

* Checkout Appearance

* Users list

* Forms

* Emails

* Pay Button

* Edit Dictionary

* Remove newlines, fix typos

* Forms

* Pull payments and payouts

* Various pages

* Use local docs link

* Fix

* Even more translations

* Fixes #6325

* Account pages

* Notifications

* Placeholders

* Various pages and components

* Add more
2024-10-25 22:48:53 +09:00

212 lines
12 KiB
Plaintext

@using BTCPayServer.HostedServices.Webhooks
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using BTCPayServer.Client
@using BTCPayServer.Abstractions.TagHelpers
@model BTCPayServer.Controllers.UIStoresController.StoreEmailRuleViewModel
@inject WebhookSender WebhookSender
@{
var storeId = Context.GetStoreData().Id;
ViewData.SetActivePage(StoreNavPages.Emails, StringLocalizer["Email Rules"], storeId);
}
@section PageHeadContent {
<link href="~/vendor/summernote/summernote-bs5.css" rel="stylesheet" asp-append-version="true" />
}
<form asp-action="StoreEmails" method="post" asp-route-storeId="@Context.GetStoreData().Id" permissioned="@Policies.CanModifyStoreSettings">
<div class="sticky-header">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a asp-action="StoreEmailSettings" asp-route-storeId="@storeId" text-translate="true">Emails</a>
</li>
<li class="breadcrumb-item active" aria-current="page" text-translate="true">@ViewData["Title"]</li>
</ol>
<h2 text-translate="true">@ViewData["Title"]</h2>
</nav>
<div permission="@Policies.CanModifyStoreSettings">
@if (Model.Rules.Any())
{
<button class="btn btn-primary" name="command" type="submit" value="save" id="SaveEmailRules" text-translate="true">
Save
</button>
}
<button class="btn btn-primary" name="command" type="submit" value="add" id="CreateEmailRule" text-translate="true">
Create
</button>
</div>
</div>
<partial name="_StatusMessage" />
<p text-translate="true">
Email rules allow BTCPay Server to send customized emails from your store based on events.
</p>
<div class="row">
<div class="col-xxl-constrain">
@if (!ViewContext.ModelState.IsValid)
{
<div asp-validation-summary="All"></div>
}
@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">
<vc:icon symbol="actions-email" />
<span text-translate="true">Test this email rule</span>
</button>
&nbsp;
<button name="command" type="submit" value="remove:@index" class="d-inline-block btn text-danger btn-link p-0">
<vc:icon symbol="actions-remove" />
<span text-translate="true">Remove this email rule</span>
</button>
</div>
</div>
<select asp-for="Rules[index].Trigger" asp-items="@WebhookSender.GetSupportedWebhookTypes().Select(s => new SelectListItem(s.Value, s.Key))" class="form-select email-rule-trigger" required></select>
<span asp-validation-for="Rules[index].Trigger" class="text-danger"></span>
<div class="form-text" text-translate="true">Choose what event sends the email.</div>
</div>
<div class="form-group">
<label asp-for="Rules[index].To" class="form-label">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" text-translate="true">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" text-translate="true">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 rounded bg-light p-2">
<table class="table table-sm caption-top m-0">
<caption class="text-muted p-0" text-translate="true">Placeholders</caption>
<tr>
<th text-translate="true">Invoice</th>
<td>
<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>
<code>{Invoice.Metadata}*</code>
</td>
</tr>
<tr>
<th text-translate="true">Request</th>
<td>
<code>{PaymentRequest.Id}</code>,
<code>{PaymentRequest.Price}</code>,
<code>{PaymentRequest.Currency}</code>,
<code>{PaymentRequest.Title}</code>,
<code>{PaymentRequest.Description}</code>,
<code>{PaymentRequest.Status}</code>
<code>{PaymentRequest.FormResponse}*</code>
</td>
</tr>
<tr>
<th text-translate="true">Payout</th>
<td>
<code>{Payout.Id}</code>,
<code>{Payout.PullPaymentId}</code>,
<code>{Payout.Destination}</code>,
<code>{Payout.State}</code>
<code>{Payout.Metadata}*</code>
</td>
</tr>
<tr><td colspan="2">* These fields are JSON objects. You can access properties within them using <a href="https://www.newtonsoft.com/json/help/html/SelectToken.htm#SelectTokenJSONPath" rel="noreferrer noopener" target="_blank">this syntax</a>. One example is <code>{Invoice.Metadata.itemCode}</code></td></tr>
</table>
</div>
</div>
</li>
}
</ul>
}
else
{
<p class="text-secondary" text-translate="true">
There are no rules yet.
</p>
}
</div>
</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>
}