Added preview for email templates

This commit is contained in:
Hillel Coren 2016-05-05 17:46:22 +03:00
parent 501958cc1e
commit c79d9fe24c
12 changed files with 188 additions and 116 deletions

View File

@ -1301,4 +1301,29 @@ class AccountController extends BaseController
return Redirect::to("/settings/$section/", 301);
}
public function previewEmail(\App\Services\TemplateService $templateService)
{
$template = Input::get('template');
$invoice = Invoice::scope()->first();
$account = Auth::user()->account;
// replace the variables with sample data
$data = [
'account' => $account,
'invoice' => $invoice,
'invitation' => $invoice->invitations->first(),
'client' => $invoice->client,
'amount' => $invoice->amount
];
// create the email view
$view = 'emails.' . $account->getTemplateView() . '_html';
$data = array_merge($data, [
'body' => $templateService->processVariables($template, $data),
'entityType' => ENTITY_INVOICE,
]);
return Response::view($view, $data);
}
}

View File

@ -208,6 +208,7 @@ Route::group([
Route::resource('tax_rates', 'TaxRateController');
Route::post('tax_rates/bulk', 'TaxRateController@bulk');
Route::get('settings/email_preview', 'AccountController@previewEmail');
Route::get('company/{section}/{subSection?}', 'AccountController@redirectLegacy');
Route::get('settings/data_visualizations', 'ReportController@d3');
Route::get('settings/charts_and_reports', 'ReportController@showReports');

View File

@ -1169,6 +1169,11 @@ class Account extends Eloquent
return str_replace('/>', ' />', $template);
}
public function getTemplateView($view = '')
{
return $this->getEmailDesignId() == EMAIL_DESIGN_PLAIN ? $view : 'design' . $this->getEmailDesignId();
}
public function getEmailFooter()
{
if ($this->email_footer) {

View File

@ -1,17 +1,13 @@
<?php namespace App\Ninja\Mailers;
use Form;
use HTML;
use Utils;
use Event;
use URL;
use Auth;
use App\Services\TemplateService;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Activity;
use App\Models\Gateway;
use App\Events\InvoiceWasEmailed;
use App\Events\QuoteWasEmailed;
@ -36,6 +32,11 @@ class ContactMailer extends Mailer
'paymentButton',
];
public function __construct(TemplateService $templateService)
{
$this->templateService = $templateService;
}
public function sendInvoice(Invoice $invoice, $reminder = false, $pdfString = false)
{
$invoice->load('invitations', 'client.language', 'account');
@ -144,7 +145,7 @@ class ContactMailer extends Mailer
}
$data = [
'body' => $this->processVariables($body, $variables),
'body' => $this->templateService->processVariables($body, $variables),
'link' => $invitation->getLink(),
'entityType' => $invoice->getEntityType(),
'invoiceId' => $invoice->id,
@ -160,14 +161,9 @@ class ContactMailer extends Mailer
$data['pdfFileName'] = $invoice->getFileName();
}
$subject = $this->processVariables($subject, $variables);
$subject = $this->templateService->processVariables($subject, $variables);
$fromEmail = $user->email;
if ($account->getEmailDesignId() == EMAIL_DESIGN_PLAIN) {
$view = ENTITY_INVOICE;
} else {
$view = 'design' . ($account->getEmailDesignId() - 1);
}
$view = $account->getTemplateView(ENTITY_INVOICE);
$response = $this->sendTo($invitation->contact->email, $fromEmail, $account->getDisplayName(), $subject, $view, $data);
@ -230,7 +226,7 @@ class ContactMailer extends Mailer
];
$data = [
'body' => $this->processVariables($emailTemplate, $variables),
'body' => $this->templateService->processVariables($emailTemplate, $variables),
'link' => $invitation->getLink(),
'invoice' => $invoice,
'client' => $client,
@ -244,14 +240,10 @@ class ContactMailer extends Mailer
$data['pdfFileName'] = $invoice->getFileName();
}
$subject = $this->processVariables($emailSubject, $variables);
$subject = $this->templateService->processVariables($emailSubject, $variables);
$data['invoice_id'] = $payment->invoice->id;
if ($account->getEmailDesignId() == EMAIL_DESIGN_PLAIN) {
$view = 'payment_confirmation';
} else {
$view = 'design' . ($account->getEmailDesignId() - 1);
}
$view = $account->getTemplateView('payment_confirmation');
if ($user->email && $contact->email) {
$this->sendTo($contact->email, $user->email, $accountName, $subject, $view, $data);
@ -281,75 +273,4 @@ class ContactMailer extends Mailer
$this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
}
private function processVariables($template, $data)
{
$account = $data['account'];
$client = $data['client'];
$invitation = $data['invitation'];
$invoice = $invitation->invoice;
$passwordHTML = isset($data['password'])?'<p>'.trans('texts.password').': '.$data['password'].'<p>':false;
$documentsHTML = '';
if($account->hasFeature(FEATURE_DOCUMENTS) && $invoice->hasDocuments()){
$documentsHTML .= trans('texts.email_documents_header').'<ul>';
foreach($invoice->documents as $document){
$documentsHTML .= '<li><a href="'.HTML::entities($document->getClientUrl($invitation)).'">'.HTML::entities($document->name).'</a></li>';
}
foreach($invoice->expenses as $expense){
foreach($expense->documents as $document){
$documentsHTML .= '<li><a href="'.HTML::entities($document->getClientUrl($invitation)).'">'.HTML::entities($document->name).'</a></li>';
}
}
$documentsHTML .= '</ul>';
}
$variables = [
'$footer' => $account->getEmailFooter(),
'$client' => $client->getDisplayName(),
'$account' => $account->getDisplayName(),
'$dueDate' => $account->formatDate($invoice->due_date),
'$invoiceDate' => $account->formatDate($invoice->invoice_date),
'$contact' => $invitation->contact->getDisplayName(),
'$firstName' => $invitation->contact->first_name,
'$amount' => $account->formatMoney($data['amount'], $client),
'$invoice' => $invoice->invoice_number,
'$quote' => $invoice->invoice_number,
'$link' => $invitation->getLink(),
'$password' => $passwordHTML,
'$viewLink' => $invitation->getLink().'$password',
'$viewButton' => Form::emailViewButton($invitation->getLink(), $invoice->getEntityType()).'$password',
'$paymentLink' => $invitation->getLink('payment').'$password',
'$paymentButton' => Form::emailPaymentButton($invitation->getLink('payment')).'$password',
'$customClient1' => $account->custom_client_label1,
'$customClient2' => $account->custom_client_label2,
'$customInvoice1' => $account->custom_invoice_text_label1,
'$customInvoice2' => $account->custom_invoice_text_label2,
'$documents' => $documentsHTML,
];
// Add variables for available payment types
foreach (Gateway::$paymentTypes as $type) {
$camelType = Gateway::getPaymentTypeName($type);
$type = Utils::toSnakeCase($camelType);
$variables["\${$camelType}Link"] = $invitation->getLink('payment') . "/{$type}";
$variables["\${$camelType}Button"] = Form::emailPaymentButton($invitation->getLink('payment') . "/{$type}");
}
$includesPasswordPlaceholder = strpos($template, '$password') !== false;
$str = str_replace(array_keys($variables), array_values($variables), $template);
if(!$includesPasswordPlaceholder && $passwordHTML){
$pos = strrpos($str, '$password');
if($pos !== false)
{
$str = substr_replace($str, $passwordHTML, $pos, 9/* length of "$password" */);
}
}
$str = str_replace('$password', '', $str);
$str = autolink($str, 100);
return $str;
}
}

View File

@ -0,0 +1,80 @@
<?php namespace App\Services;
use Form;
use HTML;
use Utils;
use App\Models\Gateway;
class TemplateService
{
public function processVariables($template, $data)
{
$account = $data['account'];
$client = $data['client'];
$invitation = $data['invitation'];
$invoice = $invitation->invoice;
$passwordHTML = isset($data['password'])?'<p>'.trans('texts.password').': '.$data['password'].'<p>':false;
$documentsHTML = '';
if ($account->hasFeature(FEATURE_DOCUMENTS) && $invoice->hasDocuments()) {
$documentsHTML .= trans('texts.email_documents_header').'<ul>';
foreach($invoice->documents as $document){
$documentsHTML .= '<li><a href="'.HTML::entities($document->getClientUrl($invitation)).'">'.HTML::entities($document->name).'</a></li>';
}
foreach($invoice->expenses as $expense){
foreach($expense->documents as $document){
$documentsHTML .= '<li><a href="'.HTML::entities($document->getClientUrl($invitation)).'">'.HTML::entities($document->name).'</a></li>';
}
}
$documentsHTML .= '</ul>';
}
$variables = [
'$footer' => $account->getEmailFooter(),
'$client' => $client->getDisplayName(),
'$account' => $account->getDisplayName(),
'$dueDate' => $account->formatDate($invoice->due_date),
'$invoiceDate' => $account->formatDate($invoice->invoice_date),
'$contact' => $invitation->contact->getDisplayName(),
'$firstName' => $invitation->contact->first_name,
'$amount' => $account->formatMoney($data['amount'], $client),
'$invoice' => $invoice->invoice_number,
'$quote' => $invoice->invoice_number,
'$link' => $invitation->getLink(),
'$password' => $passwordHTML,
'$viewLink' => $invitation->getLink().'$password',
'$viewButton' => Form::emailViewButton($invitation->getLink(), $invoice->getEntityType()).'$password',
'$paymentLink' => $invitation->getLink('payment').'$password',
'$paymentButton' => Form::emailPaymentButton($invitation->getLink('payment')).'$password',
'$customClient1' => $account->custom_client_label1,
'$customClient2' => $account->custom_client_label2,
'$customInvoice1' => $account->custom_invoice_text_label1,
'$customInvoice2' => $account->custom_invoice_text_label2,
'$documents' => $documentsHTML,
];
// Add variables for available payment types
foreach (Gateway::$paymentTypes as $type) {
$camelType = Gateway::getPaymentTypeName($type);
$type = Utils::toSnakeCase($camelType);
$variables["\${$camelType}Link"] = $invitation->getLink('payment') . "/{$type}";
$variables["\${$camelType}Button"] = Form::emailPaymentButton($invitation->getLink('payment') . "/{$type}");
}
$includesPasswordPlaceholder = strpos($template, '$password') !== false;
$str = str_replace(array_keys($variables), array_values($variables), $template);
if (!$includesPasswordPlaceholder && $passwordHTML) {
$pos = strrpos($str, '$password');
if ($pos !== false)
{
$str = substr_replace($str, $passwordHTML, $pos, 9/* length of "$password" */);
}
}
$str = str_replace('$password', '', $str);
$str = autolink($str, 100);
return $str;
}
}

View File

@ -1176,6 +1176,7 @@ $LANG = array(
'page_size' => 'Page Size',
'live_preview_disabled' => 'Live preview has been disabled to support selected font',
'invoice_number_padding' => 'Padding',
'preview' => 'Preview',
);

View File

@ -62,11 +62,14 @@
<div id="{{ $field }}_template_preview"></div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>&nbsp;<p/>
<div class="row">
<div class="col-md-10">
@include('partials/quill_toolbar', ['name' => $field])
</div>
<div class="col-md-2" style="padding-top:10px">
{!! Button::primary(trans('texts.preview'))->withAttributes(['onclick' => 'serverPreview("'.$field.'")'])->small() !!}
</div>
</div>
</div>
</div>

View File

@ -80,6 +80,26 @@
</div>
<div class="modal fade" id="templatePreviewModal" tabindex="-1" role="dialog" aria-labelledby="templatePreviewModalLabel" aria-hidden="true">
<div class="modal-dialog" style="min-width:700px">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="templatePreviewModalLabel">{{ trans('texts.preview') }}</h4>
</div>
<div class="modal-body">
<iframe id="server-preview" frameborder="1" width="100%" height="500px"/></iframe>
</div>
<div class="modal-footer" style="margin-top: 0px">
<button type="button" class="btn btn-primary" data-dismiss="modal">{{ trans('texts.close') }}</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="templateHelpModal" tabindex="-1" role="dialog" aria-labelledby="templateHelpModalLabel" aria-hidden="true">
<div class="modal-dialog" style="min-width:150px">
<div class="modal-content">
@ -158,6 +178,22 @@
}
}
function serverPreview(field) {
console.log(field);
$('#templatePreviewModal').modal('show');
var template = $('#email_template_' + field).val();
var url = '{{ URL::to('settings/email_preview') }}?template=' + template;
$('#server-preview').attr('src', url).load(function() {
// disable links in the preview
$('iframe').contents().find('a').each(function(index) {
$(this).on('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
});
});
}
$(function() {
for (var i=0; i<entityTypes.length; i++) {
var entityType = entityTypes[i];

View File

@ -12,30 +12,30 @@
</tr>
<tr>
<td style="border-collapse: collapse;">
<table cellpadding="10" cellspacing="0" border="0" bgcolor="{{ $account->primary_color ?: '#2E2B2B' }}" width="580" align="center" class="header"
style="border-bottom-width: 6px; border-bottom-color: {{ $account->primary_color ?: '#2E2B2B' }}; border-bottom-style: solid;">
<table cellpadding="10" cellspacing="0" border="0" bgcolor="#F4F5F5" width="580" align="center"
class="header" style="border-top-width: 6px; border-top-color: {{ $account->primary_color ?: '#2E2B2B' }}; border-top-style: solid;">
<tr>
<td class="logo" width="205" style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle">
<td class="logo" width="208" style="border-collapse: collapse; vertical-align: middle;" valign="middle">
@include('emails.partials.account_logo')
</td>
<td width="183" style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle">
<p class="left" style="line-height: 22px; margin: 3px 0 0; padding: 0;">
<td width="183" style="border-collapse: collapse; vertical-align: middle;" valign="middle">
<p class="left" style="line-height: 22px; margin: 0; padding: 2px 0 0;">
@if ($invoice->due_date)
<span style="font-size: 11px; color: #8f8d8e;">
{{ strtoupper(trans('texts.due_by', ['date' => $account->formatDate($invoice->due_date)])) }}
</span><br />
@endif
<span style="font-size: 19px; color: #FFFFFF;">
<span style="font-size: 18px;">
{{ trans("texts.{$entityType}") }} {{ $invoice->invoice_number }}
</span>
</p>
</td>
<td style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle">
<p style="margin: 0; padding: 0;">
<span style="font-size: 12px; color: #8f8d8e;">
{{ strtoupper(trans('texts.' . $invoice->present()->balanceDueLabel)) }}:
<td style="border-collapse: collapse; vertical-align: middle;" valign="middle">
<p class="right" style="line-height: 14px; margin: 0; padding: 0;">
<span style="font-size: 15px; color: #231F20;">
{{ trans('texts.' . $invoice->present()->balanceDueLabel) }}:
</span><br />
<span class="total" style="font-size: 27px; color: #FFFFFF; margin-top: 5px;display: block;">
<span class="total" style="font-size: 26px; display: block;margin-top: 5px;">
{{ $account->formatMoney($invoice->getRequestedAmount(), $client) }}
</span>
</p>

View File

@ -12,30 +12,30 @@
</tr>
<tr>
<td style="border-collapse: collapse;">
<table cellpadding="10" cellspacing="0" border="0" bgcolor="#F4F5F5" width="580" align="center"
class="header" style="border-top-width: 6px; border-top-color: {{ $account->primary_color ?: '#2E2B2B' }}; border-top-style: solid;">
<table cellpadding="10" cellspacing="0" border="0" bgcolor="{{ $account->primary_color ?: '#2E2B2B' }}" width="580" align="center" class="header"
style="border-bottom-width: 6px; border-bottom-color: {{ $account->primary_color ?: '#2E2B2B' }}; border-bottom-style: solid;">
<tr>
<td class="logo" width="208" style="border-collapse: collapse; vertical-align: middle;" valign="middle">
<td class="logo" width="205" style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle">
@include('emails.partials.account_logo')
</td>
<td width="183" style="border-collapse: collapse; vertical-align: middle;" valign="middle">
<p class="left" style="line-height: 22px; margin: 0; padding: 2px 0 0;">
<td width="183" style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle">
<p class="left" style="line-height: 22px; margin: 3px 0 0; padding: 0;">
@if ($invoice->due_date)
<span style="font-size: 11px; color: #8f8d8e;">
{{ strtoupper(trans('texts.due_by', ['date' => $account->formatDate($invoice->due_date)])) }}
</span><br />
@endif
<span style="font-size: 18px;">
<span style="font-size: 19px; color: #FFFFFF;">
{{ trans("texts.{$entityType}") }} {{ $invoice->invoice_number }}
</span>
</p>
</td>
<td style="border-collapse: collapse; vertical-align: middle;" valign="middle">
<p class="right" style="line-height: 14px; margin: 0; padding: 0;">
<span style="font-size: 15px; color: #231F20;">
{{ trans('texts.' . $invoice->present()->balanceDueLabel) }}:
<td style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle">
<p style="margin: 0; padding: 0;">
<span style="font-size: 12px; color: #8f8d8e;">
{{ strtoupper(trans('texts.' . $invoice->present()->balanceDueLabel)) }}:
</span><br />
<span class="total" style="font-size: 26px; display: block;margin-top: 5px;">
<span class="total" style="font-size: 27px; color: #FFFFFF; margin-top: 5px;display: block;">
{{ $account->formatMoney($invoice->getRequestedAmount(), $client) }}
</span>
</p>

View File

@ -3,7 +3,7 @@
<a href="{{ $account->website }}" style="color: #19BB40; text-decoration: underline;">
@endif
<img src="{{ $message->embed($account->getLogoURL()) }}" style="max-height:50px; max-width:140px; margin-left: 33px;" />
<img src="{{ isset($message) ? $message->embed($account->getLogoURL()) : $account->getLogoURL() }}" style="max-height:50px; max-width:140px; margin-left: 33px;" />
@if ($account->website)
</a>