diff --git a/app/Http/Livewire/BillingPortalPurchase.php b/app/Http/Livewire/BillingPortalPurchase.php index 2c57c0f12d..dd9a0c7ff7 100644 --- a/app/Http/Livewire/BillingPortalPurchase.php +++ b/app/Http/Livewire/BillingPortalPurchase.php @@ -451,7 +451,7 @@ class BillingPortalPurchase extends Component ->first(); $mailer = new NinjaMailerObject(); - $mailer->mailable = new ContactPasswordlessLogin($this->email, $this->subscription->company->id, (string)route('client.subscription.purchase', $this->subscription->hashed_id) . '?coupon=' . $this->coupon); + $mailer->mailable = new ContactPasswordlessLogin($this->email, $this->subscription->company, (string)route('client.subscription.purchase', $this->subscription->hashed_id) . '?coupon=' . $this->coupon); $mailer->company = $this->subscription->company; $mailer->settings = $this->subscription->company->settings; $mailer->to_user = $contact; diff --git a/app/Jobs/Import/CSVImport.php b/app/Jobs/Import/CSVImport.php index 9acc3255a4..2e3d40befc 100644 --- a/app/Jobs/Import/CSVImport.php +++ b/app/Jobs/Import/CSVImport.php @@ -133,7 +133,7 @@ class CSVImport implements ShouldQueue { ]; $nmo = new NinjaMailerObject; - $nmo->mailable = new ImportCompleted( $data ); + $nmo->mailable = new ImportCompleted($this->company, $data); $nmo->company = $this->company; $nmo->settings = $this->company->settings; $nmo->to_user = $this->company->owner(); diff --git a/app/Jobs/Mail/NinjaMailer.php b/app/Jobs/Mail/NinjaMailer.php index c80a7597e1..239b368c6b 100644 --- a/app/Jobs/Mail/NinjaMailer.php +++ b/app/Jobs/Mail/NinjaMailer.php @@ -37,7 +37,7 @@ class NinjaMailer extends Mailable return $this->from(config('mail.from.address'), config('mail.from.name')) ->subject($this->mail_obj->subject) - ->markdown($this->mail_obj->markdown, $this->mail_obj->data) + ->view($this->mail_obj->markdown, $this->mail_obj->data) ->withSwiftMessage(function ($message) { $message->getHeaders()->addTextHeader('Tag', $this->mail_obj->tag); }); diff --git a/app/Mail/ClientContact/ClientContactResetPasswordObject.php b/app/Mail/ClientContact/ClientContactResetPasswordObject.php index 96841d6c6c..1065b1cb6e 100644 --- a/app/Mail/ClientContact/ClientContactResetPasswordObject.php +++ b/app/Mail/ClientContact/ClientContactResetPasswordObject.php @@ -34,11 +34,12 @@ class ClientContactResetPasswordObject $data = [ 'title' => ctrans('texts.your_password_reset_link'), - 'message' => ctrans('texts.reset_password'), + 'content' => ctrans('texts.reset_password'), 'url' => route('client.password.reset', ['token' => $this->token, 'email' => $this->client_contact->email]), 'button' => ctrans('texts.reset'), 'signature' => $this->company->settings->email_signature, 'settings' => $this->company->settings, + 'company' => $this->company, 'logo' => $this->company->present()->logo(), ]; @@ -46,9 +47,9 @@ class ClientContactResetPasswordObject $mail_obj = new \stdClass; $mail_obj->subject = ctrans('texts.your_password_reset_link'); $mail_obj->data = $data; - $mail_obj->markdown = 'email.admin.generic'; + $mail_obj->markdown = 'email.client.generic'; $mail_obj->tag = $this->company->company_key; return $mail_obj; } -} \ No newline at end of file +} diff --git a/app/Mail/ContactPasswordlessLogin.php b/app/Mail/ContactPasswordlessLogin.php index e54b06b44c..d301df400f 100644 --- a/app/Mail/ContactPasswordlessLogin.php +++ b/app/Mail/ContactPasswordlessLogin.php @@ -21,25 +21,28 @@ use Illuminate\Queue\SerializesModels; class ContactPasswordlessLogin extends Mailable { - - /** - * @var string - */ + /** @var string */ public $email; + /** @var string */ public $url; + /** @var Company */ + public $company; + /** * Create a new message instance. * * @param string $email * @param string $redirect */ - public function __construct(string $email, $company_id, string $redirect = '') + public function __construct(string $email, Company $company, string $redirect = '') { $this->email = $email; - $this->url = MagicLink::create($email, $company_id, $redirect); + $this->company = $company; + + $this->url = MagicLink::create($email, $company->id, $redirect); } /** @@ -51,6 +54,10 @@ class ContactPasswordlessLogin extends Mailable { return $this ->subject(ctrans('texts.account_passwordless_login')) - ->view('email.billing.passwordless-login'); + ->view('email.billing.passwordless-login', [ + 'logo' => $this->company->present()->logo(), + 'settings' => $this->company->settings, + 'company' => $this->company->settings, + ]); } } diff --git a/app/Mail/DownloadBackup.php b/app/Mail/DownloadBackup.php index ab6d840d54..b3f287c450 100644 --- a/app/Mail/DownloadBackup.php +++ b/app/Mail/DownloadBackup.php @@ -1,4 +1,5 @@ company->company_key)->first(); return $this->from(config('mail.from.address'), config('mail.from.name')) - ->subject(ctrans('texts.download_backup_subject', ['company' => $company->present()->name()])) - ->markdown( - 'email.admin.download_files', - [ - 'url' => $this->file_path, - 'logo' => $company->present()->logo, - 'whitelabel' => $company->account->isPaid() ? true : false, - 'settings' => $company->settings, - 'greeting' => $company->present()->name(), - ] - ); + ->subject(ctrans('texts.download_backup_subject', ['company' => $company->present()->name()])) + ->view('email.admin.download_files', [ + 'url' => $this->file_path, + 'logo' => $company->present()->logo, + 'whitelabel' => $company->account->isPaid() ? true : false, + 'settings' => $company->settings, + 'greeting' => $company->present()->name(), + ]); } } diff --git a/app/Mail/DownloadInvoices.php b/app/Mail/DownloadInvoices.php index 006703f1f3..5dc1b5808c 100644 --- a/app/Mail/DownloadInvoices.php +++ b/app/Mail/DownloadInvoices.php @@ -28,14 +28,13 @@ class DownloadInvoices extends Mailable public function build() { return $this->from(config('mail.from.address'), config('mail.from.name')) - ->subject(ctrans('texts.download_files')) - ->markdown( - 'email.admin.download_files', - [ - 'url' => $this->file_path, - 'logo' => $this->company->present()->logo, - 'whitelabel' => $this->company->account->isPaid() ? true : false, - ] - ); + ->subject(ctrans('texts.download_files')) + ->view('email.admin.download_invoices', [ + 'url' => $this->file_path, + 'logo' => $this->company->present()->logo, + 'whitelabel' => $this->company->account->isPaid() ? true : false, + 'settings' => $this->company->settings, + 'greeting' => $this->company->present()->name(), + ]); } } diff --git a/app/Mail/ExistingMigration.php b/app/Mail/ExistingMigration.php index 366a4c146a..f6c80d14e0 100644 --- a/app/Mail/ExistingMigration.php +++ b/app/Mail/ExistingMigration.php @@ -39,7 +39,8 @@ class ExistingMigration extends Mailable $this->logo = $this->company->present()->logo(); $this->company_name = $this->company->present()->name(); - return $this->from(config('mail.from.address'), config('mail.from.name')) - ->view('email.migration.existing'); + return $this + ->from(config('mail.from.address'), config('mail.from.name')) + ->view('email.migration.existing'); } } diff --git a/app/Mail/Gateways/ACHVerificationNotification.php b/app/Mail/Gateways/ACHVerificationNotification.php index 6a921d9f77..3c507a434f 100644 --- a/app/Mail/Gateways/ACHVerificationNotification.php +++ b/app/Mail/Gateways/ACHVerificationNotification.php @@ -12,23 +12,27 @@ namespace App\Mail\Gateways; -use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; +use App\Models\Company; use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels; class ACHVerificationNotification extends Mailable { - use Queueable, SerializesModels; + use SerializesModels; + + /** + * @var Company + */ + public $company; /** * Create a new message instance. * * @return void */ - public function __construct() + public function __construct(Company $company) { - // + $this->company = $company; } /** @@ -38,6 +42,12 @@ class ACHVerificationNotification extends Mailable */ public function build() { - return $this->view('email.gateways.ach-verification-notification'); + return $this + ->subject(ctrans('texts.ach_verification_notification_label')) + ->view('email.gateways.ach-verification-notification', [ + 'logo' => $this->company->present()->logo(), + 'settings' => $this->company->settings, + 'company' => $this->company, + ]); } } diff --git a/app/Mail/Import/ImportCompleted.php b/app/Mail/Import/ImportCompleted.php index d3f03afa7b..b6fdbfd4f4 100644 --- a/app/Mail/Import/ImportCompleted.php +++ b/app/Mail/Import/ImportCompleted.php @@ -1,4 +1,5 @@ company = $company; + $this->data = $data; } @@ -38,7 +45,14 @@ class ImportCompleted extends Mailable */ public function build() { - return $this->from(config('mail.from.address'), config('mail.from.name')) - ->view('email.import.completed', $this->data); + $data = array_merge($this->data, [ + 'logo' => $this->company->present()->logo(), + 'settings' => $this->company->settings, + 'company' => $this->company, + ]); + + return $this + ->from(config('mail.from.address'), config('mail.from.name')) + ->view('email.import.completed', $data); } } diff --git a/app/Mail/MigrationFailed.php b/app/Mail/MigrationFailed.php index 54002a5220..9c28bd2fbc 100644 --- a/app/Mail/MigrationFailed.php +++ b/app/Mail/MigrationFailed.php @@ -2,28 +2,27 @@ namespace App\Mail; -use Illuminate\Bus\Queueable; +use App\Models\Company; use Illuminate\Mail\Mailable; -use Illuminate\Queue\SerializesModels; class MigrationFailed extends Mailable { - public $exception; + public $content; - public $settings; + public $company; + /** * Create a new message instance. * * @param $content * @param $exception */ - public function __construct($exception, $company, $content = null) + public function __construct($exception, Company $company, $content = null) { $this->exception = $exception; $this->content = $content; - $this->settings = $company->settings; $this->company = $company; } @@ -34,7 +33,11 @@ class MigrationFailed extends Mailable */ public function build() { - return $this->from(config('mail.from.address'), config('mail.from.name')) - ->view('email.migration.failed', ['settings' => $this->settings, 'company' => $this->company]); + return $this + ->from(config('mail.from.address'), config('mail.from.name')) + ->view('email.migration.failed', [ + 'logo' => $this->company->present()->logo(), + 'settings' => $this->company->settings, + ]); } } diff --git a/app/Mail/RecurringInvoice/ClientContactRequestCancellationObject.php b/app/Mail/RecurringInvoice/ClientContactRequestCancellationObject.php index ac488d5cfe..e6a4ec79de 100644 --- a/app/Mail/RecurringInvoice/ClientContactRequestCancellationObject.php +++ b/app/Mail/RecurringInvoice/ClientContactRequestCancellationObject.php @@ -35,7 +35,7 @@ class ClientContactRequestCancellationObject $data = [ 'title' => ctrans('texts.recurring_cancellation_request', ['contact' => $this->client_contact->present()->name()]), - 'message' => ctrans('texts.recurring_cancellation_request_body', ['contact' => $this->client_contact->present()->name(), 'client' => $this->client_contact->client->present()->name(), 'invoice' => $this->recurring_invoice->number]), + 'content' => ctrans('texts.recurring_cancellation_request_body', ['contact' => $this->client_contact->present()->name(), 'client' => $this->client_contact->client->present()->name(), 'invoice' => $this->recurring_invoice->number]), 'url' => config('ninja.web_url'), 'button' => ctrans('texts.account_login'), 'signature' => $this->company->settings->email_signature, diff --git a/app/Mail/SupportMessageSent.php b/app/Mail/SupportMessageSent.php index 197782f96f..e8301dfd1d 100644 --- a/app/Mail/SupportMessageSent.php +++ b/app/Mail/SupportMessageSent.php @@ -62,10 +62,11 @@ class SupportMessageSent extends Mailable return $this->from(config('mail.from.address'), config('mail.from.name')) ->replyTo($user->email, $user->present()->name()) ->subject($subject) - ->markdown('email.support.message', [ + ->view('email.support.message', [ 'message' => $this->message, 'system_info' => $system_info, 'laravel_log' => $log_lines, + 'logo' => $company->present()->logo(), ]); } } diff --git a/app/Mail/TemplateEmail.php b/app/Mail/TemplateEmail.php index 2842345f2e..6e9dc7d6dd 100644 --- a/app/Mail/TemplateEmail.php +++ b/app/Mail/TemplateEmail.php @@ -49,7 +49,8 @@ class TemplateEmail extends Mailable public function build() { - $template_name = 'email.template.'.$this->build_email->getTemplate(); + // $template_name = 'email.template.'.$this->build_email->getTemplate(); + $template_name = 'email.template.client'; if($this->build_email->getTemplate() == 'custom') { $this->build_email->setBody(str_replace('$body', $this->build_email->getBody(), $this->client->getSetting('email_style_custom'))); @@ -100,6 +101,7 @@ class TemplateEmail extends Mailable 'settings' => $settings, 'company' => $company, 'whitelabel' => $this->client->user->account->isPaid() ? true : false, + 'logo' => $this->company->present()->logo(), ]) ->withSwiftMessage(function ($message) use($company){ $message->getHeaders()->addTextHeader('Tag', $company->company_key); diff --git a/app/Mail/User/UserLoggedIn.php b/app/Mail/User/UserLoggedIn.php index 4c761f38a2..3b59d1baf6 100644 --- a/app/Mail/User/UserLoggedIn.php +++ b/app/Mail/User/UserLoggedIn.php @@ -1,4 +1,5 @@ from(config('mail.from.address'), config('mail.from.name')) - ->subject(ctrans('texts.new_login_detected')) - ->view('email.admin.notification') - ->with([ - 'settings' => $this->company->settings, - 'logo' => $this->company->present()->logo(), - 'title' => ctrans('texts.new_login_detected'), - 'body' => ctrans('texts.new_login_description', ['email' =>$this->user->email, 'ip' => $this->ip, 'time' => now()]), - 'whitelabel' => $this->company->account->isPaid(), - ]); + ->subject(ctrans('texts.new_login_detected')) + ->view('email.admin.notification') + ->with([ + 'settings' => $this->company->settings, + 'logo' => $this->company->present()->logo(), + 'title' => ctrans('texts.new_login_detected'), + 'body' => ctrans('texts.new_login_description', ['email' => $this->user->email, 'ip' => $this->ip, 'time' => now()]), + 'whitelabel' => $this->company->account->isPaid(), + ]); } } diff --git a/app/Mail/User/UserNotificationMailer.php b/app/Mail/User/UserNotificationMailer.php index b220cdb125..968051f790 100644 --- a/app/Mail/User/UserNotificationMailer.php +++ b/app/Mail/User/UserNotificationMailer.php @@ -1,4 +1,5 @@ from(config('mail.from.address'), config('mail.from.name')) - ->subject($this->mail_obj->subject) - ->markdown($this->mail_obj->markdown, $this->mail_obj->data) - ->withSwiftMessage(function ($message) { - $message->getHeaders()->addTextHeader('Tag', $this->mail_obj->tag); - }); + ->subject($this->mail_obj->subject) + ->view($this->mail_obj->markdown, $this->mail_obj->data) + ->withSwiftMessage(function ($message) { + $message->getHeaders()->addTextHeader('Tag', $this->mail_obj->tag); + }); } } diff --git a/app/PaymentDrivers/Stripe/ACH.php b/app/PaymentDrivers/Stripe/ACH.php index b92616e322..38046c92f3 100644 --- a/app/PaymentDrivers/Stripe/ACH.php +++ b/app/PaymentDrivers/Stripe/ACH.php @@ -67,12 +67,12 @@ class ACH $client_gateway_token = $this->storePaymentMethod($source, $request->input('method'), $customer); $mailer = new NinjaMailerObject(); - $mailer->mailable = new ACHVerificationNotification(); + $mailer->mailable = new ACHVerificationNotification(auth('contact')->user()->client->company); $mailer->company = auth('contact')->user()->client->company; $mailer->settings = auth('contact')->user()->client->company->settings; $mailer->to_user = auth('contact')->user(); - NinjaMailerJob::dispatchNow($mailer); + NinjaMailerJob::dispatch($mailer); return redirect()->route('client.payment_methods.verification', ['payment_method' => $client_gateway_token->hashed_id, 'method' => GatewayType::BANK_TRANSFER]); } diff --git a/app/Providers/MailCssInlinerServiceProvider.php b/app/Providers/MailCssInlinerServiceProvider.php new file mode 100644 index 0000000000..040bcd76ba --- /dev/null +++ b/app/Providers/MailCssInlinerServiceProvider.php @@ -0,0 +1,41 @@ +publishes([ + __DIR__ . '/../config/css-inliner.php' => base_path('config/css-inliner.php'), + ], 'config'); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + $this->app->singleton(CssInlinerPlugin::class, function ($app) { + return new CssInlinerPlugin([]); + }); + + $this->app->afterResolving('mail.manager', function (MailManager $mailManager) { + $mailManager->getSwiftMailer()->registerPlugin($this->app->make(CssInlinerPlugin::class)); + return $mailManager; + }); + } +} diff --git a/app/Utils/CssInlinerPlugin.php b/app/Utils/CssInlinerPlugin.php new file mode 100644 index 0000000000..0a6d8d9612 --- /dev/null +++ b/app/Utils/CssInlinerPlugin.php @@ -0,0 +1,140 @@ +converter = new CssToInlineStyles(); + $this->options = $options; + } + + /** + * @param \Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(\Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + + if ($message->getContentType() === 'text/html' + || ($message->getContentType() === 'multipart/alternative' && $message->getBody()) + || ($message->getContentType() === 'multipart/mixed' && $message->getBody()) + ) { + [$body, $cssResources] = $this->messageSieve($message->getBody()); + $css = $this->concatCss($cssResources); + $message->setBody($this->converter->convert($body, $css)); + } + + foreach ($message->getChildren() as $part) { + if (strpos($part->getContentType(), 'text/html') === 0) { + [$body, $cssResources] = $this->messageSieve($part->getBody()); + $css = $this->concatCss($cssResources); + $part->setBody($this->converter->convert($body, $css)); + } + } + } + + /** + * Do nothing + * + * @param \Swift_Events_SendEvent $evt + */ + public function sendPerformed(\Swift_Events_SendEvent $evt) + { + // Do Nothing + } + + protected function concatCss(array $cssResources): string + { + $output = ''; + foreach ($cssResources as $cssResource) { + $output.= $this->fetchCss($cssResource); + } + + return $output; + } + + protected function fetchCss(string $filename): string + { + if (isset($this->cssCache[$filename])) { + return $this->cssCache[$filename]; + } + + $fixedFilename = $filename; + // Fix relative protocols on hrefs. Assume https. + if (substr($filename, 0, 2) === '//') { + $fixedFilename = 'https:' . $filename; + } + + $content = file_get_contents($fixedFilename); + if (! $content) { + return ''; + } + + $this->cssCache[$filename] = $content; + + return $content; + } + + protected function messageSieve(string $message): array + { + $cssResources = []; + + // Initialize with config defaults, if any + if (isset($this->options['css-files'])) { + $cssResources = $this->options['css-files']; + } + + $dom = new \DOMDocument(); + // set error level + $internalErrors = libxml_use_internal_errors(true); + + $dom->loadHTML($message); + + // Restore error level + libxml_use_internal_errors($internalErrors); + $link_tags = $dom->getElementsByTagName('link'); + + /** @var \DOMElement $link */ + foreach ($link_tags as $link) { + if ($link->getAttribute('rel') === 'stylesheet') { + array_push($cssResources, $link->getAttribute('href')); + } + } + + $link_tags = $dom->getElementsByTagName('link'); + for ($i = $link_tags->length; --$i >= 0;) { + $link = $link_tags->item($i); + if ($link->getAttribute('rel') === 'stylesheet') { + $link->parentNode->removeChild($link); + } + } + + if (count($cssResources)) { + return [$dom->saveHTML(), $cssResources]; + } + + return [$message, []]; + } +} diff --git a/app/Utils/TemplateEngine.php b/app/Utils/TemplateEngine.php index 6bb5ea8e72..0b6621b7af 100644 --- a/app/Utils/TemplateEngine.php +++ b/app/Utils/TemplateEngine.php @@ -194,6 +194,7 @@ class TemplateEngine $data['title'] = ''; $data['body'] = '$body'; $data['footer'] = ''; + $data['logo'] = auth()->user()->company()->present()->logo(); $data = array_merge($data, Helpers::sharedEmailVariables($this->entity_obj->client)); @@ -211,11 +212,17 @@ class TemplateEngine } else { $wrapper = ''; } - } else { + } + elseif ($email_style == 'plain') { $wrapper = view($this->getTemplatePath($email_style), $data)->render(); $injection = ''; $wrapper = str_replace('
', $injection, $wrapper); } + else { + $wrapper = view($this->getTemplatePath('client'), $data)->render(); + $injection = ''; + $wrapper = str_replace('', $injection, $wrapper); + } $data = [ 'subject' => $this->subject, diff --git a/config/app.php b/config/app.php index b5a5b1bbab..79240cf39c 100644 --- a/config/app.php +++ b/config/app.php @@ -181,7 +181,7 @@ return [ App\Providers\MultiDBProvider::class, App\Providers\ClientPortalServiceProvider::class, App\Providers\NinjaTranslationServiceProvider::class, - + App\Providers\MailCssInlinerServiceProvider::class, ], /* diff --git a/config/css-inliner.php b/config/css-inliner.php new file mode 100644 index 0000000000..b45f64c3c8 --- /dev/null +++ b/config/css-inliner.php @@ -0,0 +1,18 @@ + [], + +]; diff --git a/public/images/emails/email.png b/public/images/emails/email.png new file mode 100644 index 0000000000..7ea6bf8c05 Binary files /dev/null and b/public/images/emails/email.png differ diff --git a/public/images/emails/forum.png b/public/images/emails/forum.png new file mode 100644 index 0000000000..836446c3c2 Binary files /dev/null and b/public/images/emails/forum.png differ diff --git a/public/images/emails/slack.png b/public/images/emails/slack.png new file mode 100644 index 0000000000..5a42af5ba7 Binary files /dev/null and b/public/images/emails/slack.png differ diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 9670fe6097..61543d9c3c 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -4254,6 +4254,16 @@ $LANG = array( 'account_passwordless_login' => 'Account passwordless login', 'user_duplicate_error' => 'Cannot add the same user to the same company', 'user_cross_linked_error' => 'User exists but cannot be crossed linked to multiple accounts', + 'ach_verification_notification_label' => 'ACH verification', + 'ach_verification_notification' => 'Connecting bank accounts require verification. Stripe will automatically sends two small deposits for this purpose. These deposits take 1-2 business days to appear on the customer\'s online statement.', + 'login_link_requested_label' => 'Login link requested', + 'login_link_requested' => 'There was a request to login using link. If you did not request this, it\'s safe to ignore it.', + 'invoices_backup_subject' => 'Your invoices are ready for download', + 'migration_failed_label' => 'Migration failed', + 'migration_failed' => 'Looks like something went wrong with the migration for the following company:', + 'client_email_company_contact_label' => 'If you have any questions please contact us, we\'re here to help!', + 'quote_was_approved_label' => 'Quote was approved', + 'quote_was_approved' => 'We would like to inform you that quote was approved.', 'company_import_failure_subject' => 'Error importing :company', 'company_import_failure_body' => 'There was an error importing the company data, the error message was:', ); diff --git a/resources/views/email/admin/download_files.blade.php b/resources/views/email/admin/download_files.blade.php index a73eace603..292208a908 100644 --- a/resources/views/email/admin/download_files.blade.php +++ b/resources/views/email/admin/download_files.blade.php @@ -1,36 +1,10 @@ -@component('email.template.master', ['design' => 'light', 'settings' =>$settings]) +@component('email.template.admin', ['logo' => $logo, 'settings' => $settings]) +{{ ctrans('texts.download_timeframe') }}
-@slot('header') - @component('email.components.header', ['p' => '', 'logo' => $logo]) - @lang('texts.download') - @endcomponent - -@endslot - - -@if(isset($greeting)) -{{ $greeting }}
-@endif - --@lang('texts.download_timeframe') -
- -- @component('email.components.button', ['url' => $url]) - @lang('texts.download') - @endcomponent -
- -@slot('signature') - InvoiceNinja (contact@invoiceninja.com) -@endslot - -@if(!$whitelabel) - @slot('footer') - @component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '© InvoiceNinja']) - For any info, please visit InvoiceNinja. - @endcomponent - @endslot -@endif -@endcomponent \ No newline at end of file + + {{ ctrans('texts.download') }} + +{{ ctrans('texts.download_timeframe') }}
+ + + {{ ctrans('texts.download') }} + +{{ $greeting }}
+ @endisset - @slot('header') - @include('email.components.header', ['logo' => $logo]) - @endslot + @isset($title) +{{ $greeting }}
- @endif + @isset($h2) +{{ $message }}
+ @isset($slot) + {{ $slot }} + @endisset +{{ $additional_info }}
+ @endisset -{{ $additional_info }}
- - @endif - - @component('email.components.button', ['url' => $url]) - @lang($button) - @endcomponent - - @if(isset($whitelabel) && !$whitelabel) - @slot('footer') - @component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '© InvoiceNinja']) - For any info, please visit InvoiceNinja. - @endcomponent - @endslot - @endif -@endcomponent + @isset($url) + {{ ctrans($button) }} + @endisset +{{ $signature }}
+ @endisset +{!! $body !!}
- - @if(isset($whitelabel) && !$whitelabel) - @slot('footer') - @component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '© InvoiceNinja']) - For any info, please visit InvoiceNinja. - @endcomponent - @endslot - @endif +@component('email.template.admin', ['logo' => $logo, 'settings' => $settings]) +{!! $body !!}
+{{ ctrans('texts.reset_password') }}
- @slot('header') - @include('email.components.header', ['logo' => $logo]) - @endslot - -{{ ctrans('texts.reset_password') }}
- - - {{ ctrans('texts.reset') }} - - - {{ $link }} + + {{ ctrans('texts.reset') }} + +{{ ctrans('texts.confirmation_message') }}
- @slot('header') - @include('email.components.header', ['logo' => 'https://www.invoiceninja.com/wp-content/uploads/2015/10/logo-white-horizontal-1.png']) - @endslot - -{{ ctrans('texts.confirmation_message') }}
- - confirmation_code}") }}" target="_blank" class="button"> - {{ ctrans('texts.confirm') }} - + confirmation_code}") }}" target="_blank" class="button"> + {{ ctrans('texts.confirm') }} + +{{ ctrans('texts.login_link_requested') }}
-Hey, there was a request to log in using link.
- - Sign in to Invoice Ninja - - Link above is only for you. Don't share it anyone. - If you didn't request this, just ignore it. - - If you can't click on the button, copy following link: - {{ $url }} + Sign in to Invoice Ninja +{{ $greeting }}
+ @endisset + + @isset($title) +{{ $additional_info }}
+ @endisset + + @isset($url) + {{ ctrans($button) }} + @endisset +Hello,
- -Connecting bank accounts require verification. Stripe will automatically sends two - small deposits for this purpose. These deposits take 1-2 business days to appear on the customer's online - statement. -
- -Thank you!
+@component('email.template.client', ['logo' => $logo, 'settings' => $settings, 'company' => $company]) +{{ ctrans('texts.ach_verification_notification') }}
+Hello, here is the output of your recent import job.
-Hello, here is the output of your recent import job.
+If your logo imported correctly it will display below. If it didn't import, you'll need to reupload your logo
-If your logo imported correctly it will display below. If it didn't import, you'll need to reupload your logo
+ - + @if(isset($company) && $company->clients->count() >=1) +{{ ctrans('texts.clients') }}: {{ $company->clients->count() }}
+ @endif - @if(isset($company) && $company->clients->count() >=1) -{{ ctrans('texts.clients') }}: {{ $company->clients->count() }}
- @endif + @if(isset($company) && count($company->products) >=1) +{{ ctrans('texts.products') }}: {{ count($company->products) }}
+ @endif - @if(isset($company) && count($company->products) >=1) -{{ ctrans('texts.products') }}: {{ count($company->products) }}
- @endif + @if(isset($company) && count($company->invoices) >=1) +{{ ctrans('texts.invoices') }}: {{ count($company->invoices) }}
+ @endif - @if(isset($company) && count($company->invoices) >=1) -{{ ctrans('texts.invoices') }}: {{ count($company->invoices) }}
- @endif + @if(isset($company) && count($company->payments) >=1) +{{ ctrans('texts.payments') }}: {{ count($company->payments) }}
+ @endif - @if(isset($company) && count($company->payments) >=1) -{{ ctrans('texts.payments') }}: {{ count($company->payments) }}
- @endif + @if(isset($company) && count($company->recurring_invoices) >=1) +{{ ctrans('texts.recurring_invoices') }}: {{ count($company->recurring_invoices) }}
+ @endif - @if(isset($company) && count($company->recurring_invoices) >=1) -{{ ctrans('texts.recurring_invoices') }}: {{ count($company->recurring_invoices) }}
- @endif + @if(isset($company) && count($company->quotes) >=1) +{{ ctrans('texts.quotes') }}: {{ count($company->quotes) }}
+ @endif - @if(isset($company) && count($company->quotes) >=1) -{{ ctrans('texts.quotes') }}: {{ count($company->quotes) }}
- @endif + @if(isset($company) && count($company->credits) >=1) +{{ ctrans('texts.credits') }}: {{ count($company->credits) }}
+ @endif - @if(isset($company) && count($company->credits) >=1) -{{ ctrans('texts.credits') }}: {{ count($company->credits) }}
- @endif + @if(isset($company) && count($company->projects) >=1) +{{ ctrans('texts.projects') }}: {{ count($company->projects) }}
+ @endif - @if(isset($company) && count($company->projects) >=1) -{{ ctrans('texts.projects') }}: {{ count($company->projects) }}
- @endif + @if(isset($company) && count($company->tasks) >=1) +{{ ctrans('texts.tasks') }}: {{ count($company->tasks) }}
+ @endif - @if(isset($company) && count($company->tasks) >=1) -{{ ctrans('texts.tasks') }}: {{ count($company->tasks) }}
- @endif + @if(isset($company) && count($company->vendors) >=1) +{{ ctrans('texts.vendors') }}: {{ count($company->vendors) }}
+ @endif - @if(isset($company) && count($company->vendors) >=1) -{{ ctrans('texts.vendors') }}: {{ count($company->vendors) }}
- @endif + @if(isset($company) && count($company->expenses) >=1) +{{ ctrans('texts.expenses') }}: {{ count($company->expenses) }}
+ @endif - @if(isset($company) && count($company->expenses) >=1) -{{ ctrans('texts.expenses') }}: {{ count($company->expenses) }}
- @endif + @if(isset($company) && count($company->company_gateways) >=1) +{{ ctrans('texts.gateways') }}: {{ count($company->company_gateways) }}
+ @endif - @if(isset($company) && count($company->company_gateways) >=1) -{{ ctrans('texts.gateways') }}: {{ count($company->company_gateways) }}
- @endif + @if(isset($company) && count($company->client_gateway_tokens) >=1) +{{ ctrans('texts.tokens') }}: {{ count($company->client_gateway_tokens) }}
+ @endif - @if(isset($company) && count($company->client_gateway_tokens) >=1) -{{ ctrans('texts.tokens') }}: {{ count($company->client_gateway_tokens) }}
- @endif + @if(isset($company) && count($company->tax_rates) >=1) +{{ ctrans('texts.tax_rates') }}: {{ count($company->tax_rates) }}
+ @endif - @if(isset($company) && count($company->tax_rates) >=1) -{{ ctrans('texts.tax_rates') }}: {{ count($company->tax_rates) }}
- @endif + @if(isset($company) && count($company->documents) >=1) +{{ ctrans('texts.documents') }}: {{ count($company->documents) }}
+ @endif - @if(isset($company) && count($company->documents) >=1) -{{ ctrans('texts.documents') }}: {{ count($company->documents) }}
- @endif + @if($check_data) +Data Quality:
+{!! $check_data !!}
+ @endif - @if(isset($check_data)) -Data Quality:
-{!! $check_data !!}
- @endif - - @if(!empty($errors) ) -{{ ctrans('texts.errors') }}:
-Type | -Data | -Error | -
---|---|---|
{{$entityType}} | -{{json_encode($error[$entityType]??null)}} | -{{json_encode($error['error'])}} | -
Type | +Data | +Error | +
---|---|---|
{{$entityType}} | +{{json_encode($error[$entityType]??null)}} | +{{json_encode($error['error'])}} | +
{{ ctrans('texts.email_signature')}}
{{ ctrans('texts.email_from') }}
{{ ctrans('texts.email_signature')}}
+{{ ctrans('texts.email_from') }}
+{{ ctrans('texts.migration_completed_description')}}
- @slot('header') - @include('email.components.header', ['logo' => 'https://www.invoiceninja.com/wp-content/uploads/2015/10/logo-white-horizontal-1.png']) - @endslot + + {{ ctrans('texts.account_login')}} + -{{ ctrans('texts.migration_completed_description')}}
- - {{ ctrans('texts.account_login')}} - -{{ ctrans('texts.email_signature')}}
{{ ctrans('texts.email_from') }}
{{ ctrans('texts.email_signature')}}
{{ ctrans('texts.email_from') }}
{{ctrans('texts.migration_already_completed_desc', ['company_name' => $company_name])}}
- - @if(isset($whitelabel) && !$whitelabel) - @slot('footer') - @component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '© InvoiceNinja']) - For any info, please visit InvoiceNinja. - @endcomponent - @endslot - @endif +@component('email.template.admin', ['logo' => $logo, 'settings' => $settings]) +{!! ctrans('texts.migration_already_completed_desc', ['company_name' => $company_name]) !!}
+{{ ctrans('texts.migration_failed') }} {{ $company->present()->name() }}
-Looks like your migration failed. Here's the error message:
- -- @if(\App\Utils\Ninja::isSelfHost()) - {!! $exception->getMessage() !!} - {!! $content !!} - @else -+Please contact us at contact@invoiceninja.com for more information on this error.
- @endif -
+ @if(\App\Utils\Ninja::isSelfHost()) + {!! $exception->getMessage() !!} + {!! $content !!} + @else ++Please contact us at contact@invoiceninja.com for more information on this error.
+ @endif +
{{ctrans('texts.max_companies_desc')}}
- - @if(isset($whitelabel) && !$whitelabel) - @slot('footer') - @component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '© InvoiceNinja']) - For any info, please visit InvoiceNinja. - @endcomponent - @endslot - @endif +@component('email.template.admin', ['logo' => $logo, 'settings' => $settings]) +{{ ctrans('texts.max_companies_desc') }}
+We want to inform you that quote was approved.
- - Visit Invoice Ninja +@component('email.template.admin', ['settings' => $settings]) +{{ ctrans('texts.quote_was_approved') }}
+
+
|
+
+
|
+