From 6771d84909079980b4a2cda41792b19d372ee785 Mon Sep 17 00:00:00 2001 From: Javier Feliz Date: Sat, 2 Aug 2025 00:22:46 -0400 Subject: [PATCH] Invitation email --- app/Livewire/ManageUsers.php | 14 ++- app/Mail/InvitationMail.php | 5 +- app/Models/Invitation.php | 5 + resources/views/emails/invitation.blade.php | 105 ++++++++++++++++++ .../views/livewire/manage-users.blade.php | 29 ++--- routes/web.php | 14 +++ 6 files changed, 155 insertions(+), 17 deletions(-) diff --git a/app/Livewire/ManageUsers.php b/app/Livewire/ManageUsers.php index 26a529b..9eaaecd 100644 --- a/app/Livewire/ManageUsers.php +++ b/app/Livewire/ManageUsers.php @@ -2,15 +2,18 @@ namespace App\Livewire; +use App\Mail\InvitationMail; use App\Models\Invitation; use App\Models\User; use Flux\Flux; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Support\Facades\Mail; use Livewire\Component; class ManageUsers extends Component { public string $invite_email = ''; + public bool $send_email = false; public Collection $users; public Collection $invitations; @@ -19,7 +22,7 @@ class ManageUsers extends Component // Only load data if user is authorized to view it if (auth()->user()->can('viewAny', User::class)) { $this->users = User::all(); - $this->invitations = Invitation::all(); + $this->invitations = Invitation::orderBy('accepted_at', 'desc')->get(); } } @@ -33,11 +36,20 @@ class ManageUsers extends Component 'invited_by' => auth()->user()->id, 'expires_at' => now()->addDays(7), ]); + + // Send email if checkbox is checked + if ($this->send_email) { + Mail::to($inv->email)->send(new InvitationMail($inv)); + } + Flux::modal('invite-user')->close(); // Refresh the data $this->invitations = Invitation::all(); $this->invite_email = ''; + $this->send_email = false; + + session()->flash('success', 'Invitation created successfully' . ($emailSent ? ' and email sent' : '') . '.'); } public function deleteUser(User $user) diff --git a/app/Mail/InvitationMail.php b/app/Mail/InvitationMail.php index ca6deeb..c4ba02a 100644 --- a/app/Mail/InvitationMail.php +++ b/app/Mail/InvitationMail.php @@ -2,6 +2,7 @@ namespace App\Mail; +use App\Models\Invitation; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Mail\Mailable; @@ -16,7 +17,7 @@ class InvitationMail extends Mailable /** * Create a new message instance. */ - public function __construct() + public function __construct(public Invitation $invitation) { // } @@ -37,7 +38,7 @@ class InvitationMail extends Mailable public function content(): Content { return new Content( - view: 'view.name', + view: 'emails.invitation', ); } diff --git a/app/Models/Invitation.php b/app/Models/Invitation.php index 99efa5d..9c2957f 100644 --- a/app/Models/Invitation.php +++ b/app/Models/Invitation.php @@ -27,4 +27,9 @@ class Invitation extends Model $this->accepted_at = now(); $this->save(); } + + public function getInviteUrl(): string + { + return route('register', ['code' => $this->code]); + } } diff --git a/resources/views/emails/invitation.blade.php b/resources/views/emails/invitation.blade.php index e69de29..7868c6a 100644 --- a/resources/views/emails/invitation.blade.php +++ b/resources/views/emails/invitation.blade.php @@ -0,0 +1,105 @@ + + + + + + You're invited to join AuthentiKate + + + +
+
+

= AuthentiKate

+

You've been invited to join our authentication platform

+
+ +
+

Hello!

+ +

You've been invited to create an account on AuthentiKate, our secure authentication platform. This will give you access to various applications and services.

+ +
+

Invitation Details:

+

Email: {{ $invitation->email }}

+

Invited by: Admin

+

Expires: {{ $invitation->expires_at->format('F j, Y \a\t g:i A') }}

+
+ +

To accept this invitation and create your account, click the button below:

+ +
+ Accept Invitation +
+ +

Or copy and paste this link into your browser:

+

+ {{ $invitation->getInviteUrl() }} +

+ +

Note: This invitation will expire on {{ $invitation->expires_at->format('F j, Y') }}. If you don't create your account by then, you'll need to request a new invitation.

+
+ + +
+ + \ No newline at end of file diff --git a/resources/views/livewire/manage-users.blade.php b/resources/views/livewire/manage-users.blade.php index e30e6b5..d8b3eee 100644 --- a/resources/views/livewire/manage-users.blade.php +++ b/resources/views/livewire/manage-users.blade.php @@ -3,19 +3,19 @@
Users
- + @if (session()->has('success')) -
- {{ session('success') }} -
+
+ {{ session('success') }} +
@endif - + @if (session()->has('error')) -
- {{ session('error') }} -
+
+ {{ session('error') }} +
@endif - + @foreach ($users as $u) @@ -30,13 +30,13 @@
@can('update', $u) - - - - + + + + @endcan @can('delete', $u) - Delete + Delete @endcan
@@ -78,6 +78,7 @@
+ Create invitation diff --git a/routes/web.php b/routes/web.php index a833d55..831b1ee 100644 --- a/routes/web.php +++ b/routes/web.php @@ -5,6 +5,7 @@ use App\Livewire\ConsentScreen; use App\Livewire\Settings\Appearance; use App\Livewire\Settings\Password; use App\Livewire\Settings\Profile; +use App\Mail\InvitationMail; use App\Models\User; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; use Illuminate\Support\Facades\Route; @@ -42,4 +43,17 @@ Route::prefix('application/o')->group(function () { }); Route::get('.well-known/jwks.json', [OIDCController::class, 'jwks'])->name('auth.keys'); Route::get('.well-known/openid-configuration', [OIDCController::class, 'openidConfig'])->name('auth.openid-configuration'); + +// Test route for invitation email preview +Route::get('/test-invitation-email', function () { + $invitation = new \App\Models\Invitation([ + 'email' => 'test@example.com', + 'code' => 'test-invitation-code-123', + 'expires_at' => now()->addDays(7), + 'invited_by' => 1, + ]); + + return new \App\Mail\InvitationMail($invitation); +})->middleware('auth'); + require __DIR__ . '/auth.php';