Email template work

This commit is contained in:
Deon George 2020-01-21 20:59:10 +11:00
parent 1767f5ac41
commit e62603a1b3
18 changed files with 799 additions and 792 deletions

View File

@ -0,0 +1,49 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
use App\Mail\TestEmail as MailTest;
use App\User;
class TestEmail extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'test:email {id}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send a test email';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$uo = User::find($this->argument('id'));
Mail::to($uo->email)
->send(new MailTest($uo));
}
}

View File

@ -25,7 +25,7 @@ class SocialLink extends Mailable
public function __construct(AccountOauth $o) public function __construct(AccountOauth $o)
{ {
$this->token = $o->link_token; $this->token = $o->link_token;
$this->user = $o; $this->user = $o->account->user;
} }
/** /**
@ -38,6 +38,8 @@ class SocialLink extends Mailable
return $this return $this
->markdown('email.system.social_link') ->markdown('email.system.social_link')
->subject('Link your Account') ->subject('Link your Account')
->with(['site'=>$this->user->site]); ->with([
'site'=>$this->user->site,
]);
} }
} }

41
app/Mail/TestEmail.php Normal file
View File

@ -0,0 +1,41 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use App\User;
class TestEmail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(User $o)
{
$this->user = $o;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this
->markdown('email.system.test_email')
->subject('Just a test...')
->with([
'site'=>$this->user->site,
'user'=>$this->user,
]);
}
}

View File

@ -76,6 +76,15 @@ class Site extends Model
return Arr::get($default,$key); return Arr::get($default,$key);
} }
public function getEmailLogoAttribute()
{
//$return = $this->getSiteDetailValue('email_logo')->value;
// @todo Get from the DB.
$return = 'site/1/gthpl-white.png';
return $return ? 'storage/'.$return : '/image/generic/150/20/fff';
}
public function getSiteLogoAttribute() public function getSiteLogoAttribute()
{ {
$return = $this->getSiteDetailValue('site_logo')->value; $return = $this->getSiteDetailValue('site_logo')->value;

View File

@ -9,9 +9,9 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^7.2", "php": "^7.2",
"barryvdh/laravel-debugbar": "^3.2",
"barryvdh/laravel-snappy": "^0.4.6", "barryvdh/laravel-snappy": "^0.4.6",
"clarkeash/doorman": "^4.0", "clarkeash/doorman": "^4.0",
"eduardokum/laravel-mail-auto-embed": "^1.0",
"fideloper/proxy": "^4.0", "fideloper/proxy": "^4.0",
"h4cc/wkhtmltoimage-amd64": "^0.12.4", "h4cc/wkhtmltoimage-amd64": "^0.12.4",
"h4cc/wkhtmltopdf-amd64": "^0.12.4", "h4cc/wkhtmltopdf-amd64": "^0.12.4",
@ -19,14 +19,15 @@
"laravel/framework": "^6.4", "laravel/framework": "^6.4",
"laravel/passport": "^8.2", "laravel/passport": "^8.2",
"laravel/socialite": "^4.2", "laravel/socialite": "^4.2",
"laravel/tinker": "^1.0",
"leenooks/laravel": "^6.0", "leenooks/laravel": "^6.0",
"spatie/laravel-demo-mode": "^2.5", "spatie/laravel-demo-mode": "^2.5",
"spinen/laravel-quickbooks-client": "^3.1" "spinen/laravel-quickbooks-client": "^3.1"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.2",
"facade/ignition": "1.11.1", "facade/ignition": "1.11.1",
"fzaninotto/faker": "^1.4", "fzaninotto/faker": "^1.4",
"laravel/tinker": "^1.0",
"mockery/mockery": "^1.0", "mockery/mockery": "^1.0",
"nunomaduro/collision": "^3.0", "nunomaduro/collision": "^3.0",
"phpunit/phpunit": "^8.0" "phpunit/phpunit": "^8.0"

935
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Mail auto embed
|--------------------------------------------------------------------------
|
| If true, images will be automatically embedded.
| If false, only images with the 'data-auto-embed' attribute will be embedded
|
*/
'enabled' => env('MAIL_AUTO_EMBED', true),
/*
|--------------------------------------------------------------------------
| Mail embed method
|--------------------------------------------------------------------------
|
| Supported: "attachment", "base64"
|
*/
'method' => env('MAIL_AUTO_EMBED_METHOD', 'attachment'),
];

View File

@ -132,5 +132,6 @@ return [
*/ */
'log_channel' => env('MAIL_LOG_CHANNEL'), 'log_channel' => env('MAIL_LOG_CHANNEL'),
'local_domain' => env('MAIL_HOST'),
]; ];

View File

@ -1,10 +1,8 @@
@component('mail::message',['site'=>$site]) @component('mail::message',['site'=>$site,'heading'=>'Link Your Account'])
Howdy, Hi {{ isset($user) ? $user->name.',' : '' }}
A request was made to link your account to a social login. A request was made to link your account to a social login.
If you didnt make this request, you can ignore this, and the request will be ignored. If you didnt make this request, you can ignore this, and the request will be ignored.
If you did make the request, then please enter the code displayed below. If you did make the request, then please enter the code displayed below.
@component('mail::panel') @component('mail::panel')
@ -13,6 +11,11 @@ If you did make the request, then please enter the code displayed below.
Once you've keyed in this code, you'll be able to login to your account using your social login instead of a username and a password. Once you've keyed in this code, you'll be able to login to your account using your social login instead of a username and a password.
Thanks,<br> Thanks,
{{ config('app.name') }}
{{ config('mail.from.name') }}
@component('mail::subcopy')
If you didnt make this request, you can safely ignore this email - no change was made to your account, nor was it accessed by an unauthorised person.
@endcomponent
@endcomponent @endcomponent

View File

@ -0,0 +1,11 @@
@component('mail::message',['site'=>$site,'heading'=>'System Test Email'])
Hi {{ isset($user) ? $user->name.',' : '' }}
This is just a test email to validate that you can receive emails from us.
Nothing you need to do!
Thanks,
{{ config('mail.from.name') }}
@endcomponent

View File

@ -0,0 +1,3 @@
<div class="footer">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</div>

View File

@ -1,7 +1,6 @@
<tr> <div class="header">
<td class="header"> <div class="fixedw">
<a href="{{ $url }}"> <img src="{{ $logo }}"><br>
<img class="pull-left" src="{{ $logo }}"> <div class="pull-right">{{ $slot }}</div> <div class="subject">{{ $slot }}</div>
</a> </div>
</td> </div>
</tr>

View File

@ -3,54 +3,23 @@
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="color-scheme" content="light only">
<meta name="supported-color-schemes" content="light only">
<link href='http://fonts.googleapis.com/css?family=Bree+Serif' rel='stylesheet' type='text/css'>
<link href="http://fonts.googleapis.com/css?family=Roboto:400,300,100,500,700,900,400italic,300italic" rel="stylesheet" type="text/css">
</head> </head>
<body> <body>
<style> {{ $header ?? '' }}
@media only screen and (max-width: 600px) {
.inner-body {
width: 100% !important;
}
.footer { <section class="content">
width: 100% !important; <div class="fixedw main-body">
} {{ Illuminate\Mail\Markdown::parse($slot) }}
} </div>
@media only screen and (max-width: 500px) { {{ $subcopy ?? '' }}
.button { </section>
width: 100% !important;
}
}
</style>
<table class="wrapper" width="100%" cellpadding="0" cellspacing="0"> {{ $footer ?? '' }}
<tr>
<td width="15%">&nbsp;</td>
<td align="center">
<table class="content" width="100%" cellpadding="0" cellspacing="0">
{{ $header ?? '' }}
<!-- Email Body -->
<tr>
<td class="body" width="100%" cellpadding="0" cellspacing="0">
<table class="inner-body" align="center" width="570" cellpadding="0" cellspacing="0">
<!-- Body content -->
<tr>
<td class="content-cell">
{{ Illuminate\Mail\Markdown::parse($slot) }}
{{ $subcopy ?? '' }}
</td>
</tr>
</table>
</td>
</tr>
{{ $footer ?? '' }}
</table>
</td>
<td width="15%">&nbsp;</td>
</tr>
</table>
</body> </body>
</html> </html>

View File

@ -1,8 +1,8 @@
@component('mail::layout') @component('mail::layout')
{{-- Header --}} {{-- Header --}}
@slot('header') @slot('header')
@component('mail::header', ['url' => config('app.url'),'logo'=>url($site->site_logo)]) @component('mail::header', ['url' => config('app.url'),'logo'=>url($site->email_logo)])
{{ $site->site_name }} {{ $heading }}
@endcomponent @endcomponent
@endslot @endslot
@ -21,7 +21,11 @@
{{-- Footer --}} {{-- Footer --}}
@slot('footer') @slot('footer')
@component('mail::footer') @component('mail::footer')
&copy; {{ date('Y') }} {{ config('app.name') }}. All rights reserved. <div class="fixedw" style="text-align: right; font-size: 0.8em;">
{{ config('mail.from.name') }}<br>
{!! $site->address('html') !!}<br>
{{ $site->site_email }}
</div>
@endcomponent @endcomponent
@endslot @endslot
@endcomponent @endcomponent

View File

@ -0,0 +1,5 @@
<div style="margin: auto; text-align: center; padding-bottom: 20px;">
<div class="panel">
{{ $slot }}
</div>
</div>

View File

@ -0,0 +1,3 @@
<div class="light-box">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</div>

View File

@ -1,299 +1,123 @@
/* Base */ body{
body, body *:not(html):not(style):not(br):not(tr):not(code) {
font-family: Avenir, Helvetica, sans-serif;
box-sizing: border-box;
}
body {
background-color: #f5f8fa;
color: #74787E;
height: 100%;
hyphens: auto;
line-height: 1.4;
margin: 0;
-moz-hyphens: auto;
-ms-word-break: break-all;
width: 100% !important;
-webkit-hyphens: auto;
-webkit-text-size-adjust: none;
word-break: break-all;
word-break: break-word;
}
p,
ul,
ol,
blockquote {
line-height: 1.4;
text-align: left;
}
a {
color: #3869D4;
}
a img {
border: none;
}
/* Typography */
h1 {
color: #2F3133;
font-size: 19px;
font-weight: bold;
margin-top: 0;
text-align: left;
}
h2 {
color: #2F3133;
font-size: 16px;
font-weight: bold;
margin-top: 0;
text-align: left;
}
h3 {
color: #2F3133;
font-size: 14px;
font-weight: bold;
margin-top: 0;
text-align: left;
}
p {
color: #74787E;
font-size: 16px;
line-height: 1.5em;
margin-top: 0;
text-align: left;
}
p.sub {
font-size: 12px;
}
img {
max-width: 100%;
}
/* Layout */
.wrapper {
background-color: #f5f8fa;
margin: 0;
padding: 0;
width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
}
.content {
margin: 0;
padding: 0;
width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
}
/* Header */
.header {
padding: 25px 0;
text-align: center;
}
.header a {
color: #bbbfc3;
font-size: 19px;
font-weight: bold;
text-decoration: none;
text-shadow: 0 1px 0 white;
}
.header img {
height: 35px;
}
/* Body */
.body {
background-color: #FFFFFF;
border-bottom: 1px solid #EDEFF2;
border-top: 1px solid #EDEFF2;
margin: 0;
padding: 0;
width: 580px;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
}
.inner-body {
background-color: #FFFFFF;
margin: 0 auto; margin: 0 auto;
padding: 0; font-family: 'Bree Serif';
width: 570px; background: #f4f4f4;
-premailer-cellpadding: 0; color: #6c7584;
-premailer-cellspacing: 0; font-size: 1.2em;
-premailer-width: 570px;
} }
.header{
.pull-right { background: #232323;
float: right; border-bottom: 5px solid #454d59;
padding: 20px 0px 10px 0px;
margin-bottom: 30px;
color: #f4f4f4;
font-weight: 300;
} }
.footer{
.pull-left { background: #232323;
float: left; border-top: 5px solid #454d59;
padding: 10px 0px 20px 0px;
margin-top: 30px;
color: #f4f4f4;
font-weight: 100;
} }
.subject{
/* Subcopy */ font-weight: 300;
font-family: 'Bree Serif',serif;
.subcopy { font-size: 1.5em;
border-top: 1px solid #EDEFF2; /* text-align: right; */
margin-top: 25px;
padding-top: 25px;
} }
.panel{
.subcopy p { background:#454d59;
font-size: 12px; border-radius: 10px;
padding: 20px;
font-weight: 300;
color: #f4f4f4;
font-size: 1.4em;
display: inline-block
} }
.light-box{
/* Footer */ background: #f9f9f9;
border-radius: 10px;
.footer { padding: 10px;
margin: 0 auto; font-weight: 300;
padding: 0; margin-top: 20px;
text-align: center; font-size: 0.8em;
width: 570px;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 570px;
} }
.main-body{
.footer p { background: #ffffff;
color: #AEAEAE; border-radius: 10px;
font-size: 12px; color:#6c7584;
text-align: center; font-weight: 400;
padding:10px 20px;
border-top:1px solid #dbdbdb;
border-left:1px solid #dbdbdb;
border-right:1px solid #dbdbdb;
border-bottom:3px solid #dbdbdb;
} }
.main-body table thead td{
font-weight: 300;
border-bottom: 1px solid #dbdbdb;
color: #ccc
}
.main-body table td.title{
font-size: 1.1em;
line-height: 20px;
}
.main-body table td.title small{
font-weight: 300;
font-size: 0.9em;
color: #6c7584
}
.main-body .note{
font-size: 0.8em;
font-weight: 300;
font-style: normal;
}
/* -- TO VALIDATE -- */
a{
text-decoration: underline;
color: #1cbbb4
}
a:hover{text-decoration: none;}
/* Tables */ h1{
font-weight: 300;
.table table { color: #121212;
font-family: 'Bree Serif',serif;
margin:0 auto;
font-size: 32px;
}
h1 small{font-weight: 200; font-size: 24px;}
h3{
font-weight: 300;
color: #121212;
font-family: 'Bree Serif',serif;
margin: 25px auto;
font-size: 24px;
}
.free{color:#1cbbb4;}
.paid{color:#0f80bb;}
.links{
margin: 30px auto; margin: 30px auto;
width: 100%; width: 600px;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
} }
.links table td{
.table th { padding: 20px;
border-bottom: 1px solid #EDEFF2;
padding-bottom: 8px;
margin: 0;
}
.table td {
color: #74787E;
font-size: 15px;
line-height: 18px;
padding: 10px 0;
margin: 0;
}
.content-cell {
padding: 15px;
}
/* Buttons */
.action {
margin: 30px auto;
padding: 0;
text-align: center;
width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
}
.button {
border-radius: 3px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16);
color: #FFF;
display: inline-block;
text-decoration: none;
-webkit-text-size-adjust: none;
}
.button-blue {
background-color: #3097D1;
border-top: 10px solid #3097D1;
border-right: 18px solid #3097D1;
border-bottom: 10px solid #3097D1;
border-left: 18px solid #3097D1;
}
.button-green {
background-color: #2ab27b;
border-top: 10px solid #2ab27b;
border-right: 18px solid #2ab27b;
border-bottom: 10px solid #2ab27b;
border-left: 18px solid #2ab27b;
}
.button-red {
background-color: #bf5329;
border-top: 10px solid #bf5329;
border-right: 18px solid #bf5329;
border-bottom: 10px solid #bf5329;
border-left: 18px solid #bf5329;
}
/* Panels */
.panel {
margin: 0 0 21px;
}
.panel-content {
background-color: #EDEFF2;
padding: 16px;
}
.panel-item {
padding: 0;
}
.panel-item p:last-of-type {
margin-bottom: 0;
padding-bottom: 0;
}
/* Promotions */
.promotion {
background-color: #FFFFFF;
border: 2px dashed #9BA2AB;
margin: 0;
margin-bottom: 25px;
margin-top: 25px;
padding: 24px;
width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
}
.promotion h1 {
text-align: center;
}
.promotion p {
font-size: 15px;
text-align: center; text-align: center;
font-weight: 300;
color: #333;
font-size:18px;
} }
.links table td span, .links table td a{font-weight: 400}
.border-l{border-left:1px solid #ccc}
.apikey{font-size: 18px; color:#333}
.apikey p{border-bottom: 1px solid #dbdbdb; padding: 10px 0 10px 0;margin: 0 0;}
.apikey p.last{border-bottom: none}
.apikey small{font-size: 80%; font-weight: 300}
.twitter{padding: 20px; font-weight: 300;font-size:16px;}
.fixedw{width: 80%; margin: 0 auto;}
.right{float:right}
.left{float:left}
.clear{clear: both;}
table thead td {font-size: 16px;}