Compare commits
1 Commits
docs/add-f
...
feature/em
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b86e5fd22 |
63
app/Filament/Resources/EmailTemplateResource.php
Normal file
63
app/Filament/Resources/EmailTemplateResource.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\EmailTemplateResource\Pages\CreateEmailTemplate;
|
||||
use App\Filament\Resources\EmailTemplateResource\Pages\EditEmailTemplate;
|
||||
use App\Filament\Resources\EmailTemplateResource\Pages\ListEmailTemplates;
|
||||
use App\Filament\Resources\EmailTemplateResource\Pages\ViewEmailTemplate;
|
||||
use App\Filament\Resources\EmailTemplateResource\Schemas\EmailTemplateForm;
|
||||
use App\Filament\Resources\EmailTemplateResource\Schemas\EmailTemplateInfolist;
|
||||
use App\Filament\Resources\EmailTemplateResource\Tables\EmailTemplatesTable;
|
||||
use App\Models\EmailTemplate;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class EmailTemplateResource extends Resource
|
||||
{
|
||||
protected static ?string $model = EmailTemplate::class;
|
||||
|
||||
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-envelope';
|
||||
|
||||
protected static \UnitEnum|string|null $navigationGroup = 'System';
|
||||
|
||||
protected static ?int $navigationSort = 10;
|
||||
|
||||
protected static ?string $navigationLabel = 'Email Templates';
|
||||
|
||||
protected static ?string $modelLabel = 'Email Template';
|
||||
|
||||
protected static ?string $pluralModelLabel = 'Email Templates';
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
{
|
||||
// Count inactive templates
|
||||
return static::getModel()::where('is_active', false)->count() ?: null;
|
||||
}
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return EmailTemplateForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return EmailTemplateInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return EmailTemplatesTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListEmailTemplates::route('/'),
|
||||
'create' => CreateEmailTemplate::route('/create'),
|
||||
'view' => ViewEmailTemplate::route('/{record}'),
|
||||
'edit' => EditEmailTemplate::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmailTemplateResource\Pages;
|
||||
|
||||
use App\Filament\Resources\EmailTemplateResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateEmailTemplate extends CreateRecord
|
||||
{
|
||||
protected static string $resource = EmailTemplateResource::class;
|
||||
|
||||
protected function getRedirectUrl(): string
|
||||
{
|
||||
return $this->getResource()::getUrl('index');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmailTemplateResource\Pages;
|
||||
|
||||
use App\Filament\Resources\EmailTemplateResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditEmailTemplate extends EditRecord
|
||||
{
|
||||
protected static string $resource = EmailTemplateResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getRedirectUrl(): string
|
||||
{
|
||||
return $this->getResource()::getUrl('index');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmailTemplateResource\Pages;
|
||||
|
||||
use App\Filament\Resources\EmailTemplateResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListEmailTemplates extends ListRecords
|
||||
{
|
||||
protected static string $resource = EmailTemplateResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmailTemplateResource\Pages;
|
||||
|
||||
use App\Filament\Resources\EmailTemplateResource;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewEmailTemplate extends ViewRecord
|
||||
{
|
||||
protected static string $resource = EmailTemplateResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
EditAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmailTemplateResource\Schemas;
|
||||
|
||||
use App\Models\EmailTemplate;
|
||||
use Filament\Forms\Components\Checkbox;
|
||||
use Filament\Forms\Components\Placeholder;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class EmailTemplateForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->columns(1)
|
||||
->components([
|
||||
Section::make('Template Details')
|
||||
->schema([
|
||||
TextInput::make('key')
|
||||
->label('Template Key')
|
||||
->required()
|
||||
->unique(ignoreRecord: true)
|
||||
->regex('/^[a-z0-9_-]+$/')
|
||||
->helperText('Lowercase alphanumeric characters, hyphens and underscores only')
|
||||
->disabled(fn ($context) => $context === 'edit')
|
||||
->dehydrated(fn ($context) => $context === 'create')
|
||||
->columnSpanFull(),
|
||||
|
||||
TextInput::make('name')
|
||||
->label('Template Name')
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->columnSpanFull(),
|
||||
|
||||
TextInput::make('subject')
|
||||
->label('Email Subject')
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->columnSpanFull(),
|
||||
|
||||
Textarea::make('description')
|
||||
->label('Description')
|
||||
->helperText('Describe when this template is used')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
|
||||
TextInput::make('available_variables')
|
||||
->label('Available Variables')
|
||||
->helperText('Comma-separated list (e.g., verification_url, email, logo_url)')
|
||||
->afterStateHydrated(function (TextInput $component, $state) {
|
||||
if (is_array($state)) {
|
||||
$component->state(implode(', ', $state));
|
||||
}
|
||||
})
|
||||
->dehydrateStateUsing(function ($state) {
|
||||
if (empty($state)) {
|
||||
return [];
|
||||
}
|
||||
return array_map('trim', explode(',', $state));
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
Checkbox::make('is_active')
|
||||
->label('Template is Active')
|
||||
->default(true)
|
||||
->inline(false),
|
||||
])
|
||||
->columns(2),
|
||||
|
||||
Section::make('Email Content')
|
||||
->schema([
|
||||
Textarea::make('body_html')
|
||||
->label('HTML Body')
|
||||
->required()
|
||||
->rows(25)
|
||||
->helperText('Use {{ $variable }} syntax for dynamic content')
|
||||
->columnSpanFull()
|
||||
->extraAttributes(['style' => 'font-family: monospace; font-size: 13px;']),
|
||||
|
||||
Textarea::make('body_text')
|
||||
->label('Plain Text Body (Optional)')
|
||||
->rows(15)
|
||||
->helperText('Plain text fallback for email clients that don\'t support HTML')
|
||||
->columnSpanFull()
|
||||
->extraAttributes(['style' => 'font-family: monospace; font-size: 13px;']),
|
||||
]),
|
||||
|
||||
Section::make('Metadata')
|
||||
->schema([
|
||||
Placeholder::make('created_at')
|
||||
->label('Created At')
|
||||
->content(fn (?EmailTemplate $record): string => $record?->created_at?->diffForHumans() ?? '-'),
|
||||
|
||||
Placeholder::make('updated_at')
|
||||
->label('Last Updated')
|
||||
->content(fn (?EmailTemplate $record): string => $record?->updated_at?->diffForHumans() ?? '-'),
|
||||
])
|
||||
->columns(2)
|
||||
->hidden(fn ($context) => $context === 'create'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmailTemplateResource\Schemas;
|
||||
|
||||
use Filament\Infolists\Components\IconEntry;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Infolists\Components\ViewEntry;
|
||||
use Filament\Schemas\Schema;
|
||||
use Illuminate\Support\HtmlString;
|
||||
|
||||
class EmailTemplateInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextEntry::make('name')
|
||||
->label('Template Name')
|
||||
->columnSpan(1),
|
||||
|
||||
TextEntry::make('key')
|
||||
->label('Template Key')
|
||||
->badge()
|
||||
->copyable()
|
||||
->copyMessage('Key copied!')
|
||||
->copyMessageDuration(1500)
|
||||
->columnSpan(1),
|
||||
|
||||
TextEntry::make('subject')
|
||||
->label('Email Subject')
|
||||
->columnSpan(2),
|
||||
|
||||
TextEntry::make('description')
|
||||
->label('Description')
|
||||
->columnSpan(2)
|
||||
->placeholder('No description provided'),
|
||||
|
||||
TextEntry::make('available_variables')
|
||||
->label('Available Variables')
|
||||
->badge()
|
||||
->separator(',')
|
||||
->columnSpan(2)
|
||||
->placeholder('No variables defined'),
|
||||
|
||||
IconEntry::make('is_active')
|
||||
->label('Status')
|
||||
->boolean()
|
||||
->trueIcon('heroicon-o-check-circle')
|
||||
->falseIcon('heroicon-o-x-circle')
|
||||
->trueColor('success')
|
||||
->falseColor('danger')
|
||||
->columnSpan(1),
|
||||
|
||||
TextEntry::make('created_at')
|
||||
->label('Created')
|
||||
->dateTime()
|
||||
->since()
|
||||
->columnSpan(1),
|
||||
|
||||
TextEntry::make('updated_at')
|
||||
->label('Last Updated')
|
||||
->dateTime()
|
||||
->since()
|
||||
->columnSpan(1),
|
||||
|
||||
ViewEntry::make('preview')
|
||||
->label('HTML Preview')
|
||||
->viewData(fn ($record) => [
|
||||
'html' => $record->body_html,
|
||||
])
|
||||
->view('filament.email-template-preview')
|
||||
->columnSpan(2),
|
||||
|
||||
TextEntry::make('body_html')
|
||||
->label('HTML Source')
|
||||
->formatStateUsing(fn ($state) => new HtmlString('<pre class="text-xs font-mono bg-gray-100 dark:bg-gray-900 p-4 rounded overflow-x-auto whitespace-pre-wrap">' . htmlspecialchars($state) . '</pre>'))
|
||||
->columnSpan(2),
|
||||
|
||||
TextEntry::make('body_text')
|
||||
->label('Plain Text Version')
|
||||
->formatStateUsing(fn ($state) => new HtmlString('<pre class="text-xs font-mono bg-gray-100 dark:bg-gray-900 p-4 rounded overflow-x-auto whitespace-pre-wrap">' . htmlspecialchars($state ?: 'No plain text version') . '</pre>'))
|
||||
->columnSpan(2)
|
||||
->hidden(fn ($record) => empty($record->body_text)),
|
||||
])
|
||||
->columns(2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmailTemplateResource\Tables;
|
||||
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class EmailTemplatesTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->label('Template Name')
|
||||
->searchable()
|
||||
->sortable()
|
||||
->weight('bold'),
|
||||
|
||||
TextColumn::make('key')
|
||||
->label('Key')
|
||||
->searchable()
|
||||
->sortable()
|
||||
->fontFamily('mono')
|
||||
->size('sm')
|
||||
->copyable()
|
||||
->copyMessage('Key copied!')
|
||||
->copyMessageDuration(1500),
|
||||
|
||||
TextColumn::make('subject')
|
||||
->label('Subject')
|
||||
->searchable()
|
||||
->limit(50)
|
||||
->wrap(),
|
||||
|
||||
IconColumn::make('is_active')
|
||||
->label('Status')
|
||||
->boolean()
|
||||
->trueIcon('heroicon-o-check-circle')
|
||||
->falseIcon('heroicon-o-x-circle')
|
||||
->trueColor('success')
|
||||
->falseColor('danger')
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('updated_at')
|
||||
->label('Last Updated')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->since()
|
||||
->size('sm'),
|
||||
])
|
||||
->defaultSort('name')
|
||||
->filters([
|
||||
SelectFilter::make('is_active')
|
||||
->label('Status')
|
||||
->options([
|
||||
true => 'Active',
|
||||
false => 'Inactive',
|
||||
]),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
67
app/Models/EmailTemplate.php
Normal file
67
app/Models/EmailTemplate.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class EmailTemplate extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'key',
|
||||
'name',
|
||||
'subject',
|
||||
'body_html',
|
||||
'body_text',
|
||||
'available_variables',
|
||||
'description',
|
||||
'is_active',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'available_variables' => 'array',
|
||||
'is_active' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get a template by its key
|
||||
*/
|
||||
public static function getByKey(string $key): ?self
|
||||
{
|
||||
return self::where('key', $key)
|
||||
->where('is_active', true)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the template with provided variables
|
||||
*/
|
||||
public function render(array $variables = []): string
|
||||
{
|
||||
$html = $this->body_html;
|
||||
|
||||
foreach ($variables as $key => $value) {
|
||||
$html = str_replace('{{ $' . $key . ' }}', $value, $html);
|
||||
$html = str_replace('{{$' . $key . '}}', $value, $html);
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the subject with provided variables
|
||||
*/
|
||||
public function renderSubject(array $variables = []): string
|
||||
{
|
||||
$subject = $this->subject;
|
||||
|
||||
foreach ($variables as $key => $value) {
|
||||
$subject = str_replace('{{ $' . $key . ' }}', $value, $subject);
|
||||
$subject = str_replace('{{$' . $key . '}}', $value, $subject);
|
||||
}
|
||||
|
||||
return $subject;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\EmailTemplate;
|
||||
use App\Models\EmailVerification;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
@@ -72,9 +73,29 @@ class EmailVerificationService
|
||||
*/
|
||||
public function sendVerificationEmail(string $email, string $token): void
|
||||
{
|
||||
$verificationUrl = route('buyer.register.verify', ['token' => $token]);
|
||||
$verificationUrl = route('buyer.register.complete', ['token' => $token]);
|
||||
|
||||
Mail::to($email)->send(new \App\Mail\RegistrationVerificationMail($verificationUrl, $email));
|
||||
// Try to use database template first, fall back to mailable if not found
|
||||
$template = EmailTemplate::getByKey('registration_verification');
|
||||
|
||||
if ($template) {
|
||||
$variables = [
|
||||
'verification_url' => $verificationUrl,
|
||||
'email' => $email,
|
||||
'logo_url' => asset('assets/images/canna_white.png'),
|
||||
'account_name' => 'Cannabrands',
|
||||
'support_email' => 'hello@cannabrands.com',
|
||||
];
|
||||
|
||||
Mail::send([], [], function ($message) use ($template, $email, $variables) {
|
||||
$message->to($email)
|
||||
->subject($template->renderSubject($variables))
|
||||
->html($template->render($variables));
|
||||
});
|
||||
} else {
|
||||
// Fallback to original mailable
|
||||
Mail::to($email)->send(new \App\Mail\RegistrationVerificationMail($verificationUrl, $email));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('email_templates', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('key')->unique()->comment('Unique identifier for the template');
|
||||
$table->string('name')->comment('Human-readable name');
|
||||
$table->string('subject');
|
||||
$table->text('body_html')->comment('HTML version of email');
|
||||
$table->text('body_text')->nullable()->comment('Plain text version');
|
||||
$table->json('available_variables')->nullable()->comment('List of variables that can be used in this template');
|
||||
$table->text('description')->nullable()->comment('Description of when this template is used');
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('email_templates');
|
||||
}
|
||||
};
|
||||
181
database/seeders/EmailTemplateSeeder.php
Normal file
181
database/seeders/EmailTemplateSeeder.php
Normal file
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\EmailTemplate;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class EmailTemplateSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Registration Verification Email
|
||||
EmailTemplate::updateOrCreate(
|
||||
['key' => 'registration_verification'],
|
||||
[
|
||||
'name' => 'Registration Verification',
|
||||
'subject' => 'Complete Your Cannabrands Registration',
|
||||
'body_html' => $this->getRegistrationVerificationHtml(),
|
||||
'body_text' => $this->getRegistrationVerificationText(),
|
||||
'available_variables' => [
|
||||
'verification_url',
|
||||
'email',
|
||||
'logo_url',
|
||||
'account_name',
|
||||
'support_email',
|
||||
],
|
||||
'description' => 'Sent to users when they start the registration process to verify their email address.',
|
||||
'is_active' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->command->info('Email templates seeded successfully!');
|
||||
}
|
||||
|
||||
private function getRegistrationVerificationHtml(): string
|
||||
{
|
||||
return <<<'HTML'
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: #f4f5f7;
|
||||
font-family: Arial, sans-serif;
|
||||
color: #172B4D;
|
||||
}
|
||||
.main {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
background: #ffffff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #014847 0%, #014342 100%);
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
.header img {
|
||||
height: 32px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.header h1 {
|
||||
font-size: 24px;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
font-weight: normal;
|
||||
}
|
||||
.content {
|
||||
padding: 30px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.content p {
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
.highlight-box {
|
||||
background: #f1f5f9;
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.button-container {
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
background-color: #015b59;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
padding: 14px 28px;
|
||||
font-weight: bold;
|
||||
border-radius: 5px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: #014847;
|
||||
}
|
||||
.footer {
|
||||
padding: 30px;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
color: #6b7280;
|
||||
}
|
||||
.footer a {
|
||||
color: #015b59;
|
||||
text-decoration: none;
|
||||
}
|
||||
.expiry-note {
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main">
|
||||
<div class="header">
|
||||
<img src="{{ $logo_url }}" alt="{{ $account_name }} Logo" />
|
||||
<h1>Complete Your Registration</h1>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>Hello,</p>
|
||||
|
||||
<p>Thank you for starting your registration with {{ $account_name }}! To complete your account setup, please click the button below to verify your email address and fill out your profile.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>Email:</strong> {{ $email }}
|
||||
</div>
|
||||
|
||||
<div class="button-container">
|
||||
<a href="{{ $verification_url }}" class="button">Complete Registration</a>
|
||||
</div>
|
||||
|
||||
<p class="expiry-note">
|
||||
⏱️ This link will expire in 24 hours for security reasons.
|
||||
</p>
|
||||
|
||||
<p>If you didn't request this registration, you can safely ignore this email.</p>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<p>Need help?</p>
|
||||
<p>Contact us at <a href="mailto:{{ $support_email }}">{{ $support_email }}</a>.</p>
|
||||
<p>– The {{ $account_name }} Team</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
}
|
||||
|
||||
private function getRegistrationVerificationText(): string
|
||||
{
|
||||
return <<<'TEXT'
|
||||
Complete Your Registration
|
||||
|
||||
Hello,
|
||||
|
||||
Thank you for starting your registration with {{ $account_name }}! To complete your account setup, please visit the link below to verify your email address and fill out your profile.
|
||||
|
||||
Email: {{ $email }}
|
||||
|
||||
Complete your registration here:
|
||||
{{ $verification_url }}
|
||||
|
||||
⏱️ This link will expire in 24 hours for security reasons.
|
||||
|
||||
If you didn't request this registration, you can safely ignore this email.
|
||||
|
||||
Need help?
|
||||
Contact us at {{ $support_email }}.
|
||||
|
||||
– The {{ $account_name }} Team
|
||||
TEXT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<div class="w-full">
|
||||
<iframe
|
||||
srcdoc="{{ $html }}"
|
||||
class="w-full border-2 border-gray-200 dark:border-gray-700 rounded-lg bg-white"
|
||||
style="min-height: 600px; width: 100%;"
|
||||
></iframe>
|
||||
</div>
|
||||
Reference in New Issue
Block a user