Ability to remove invitations
Some checks failed
linter / quality (push) Successful in 3m22s
tests / ci (push) Failing after 7m42s

This commit is contained in:
Javier Feliz 2025-08-02 00:28:49 -04:00
parent 6771d84909
commit 8c3c2105dd
4 changed files with 57 additions and 15 deletions

View File

@ -45,11 +45,12 @@ class ManageUsers extends Component
Flux::modal('invite-user')->close();
// Refresh the data
$this->invitations = Invitation::all();
$this->invitations->prepend($inv);
$this->reset(['invite_email', 'send_email']);
$this->invite_email = '';
$this->send_email = false;
session()->flash('success', 'Invitation created successfully' . ($emailSent ? ' and email sent' : '') . '.');
session()->flash('success', 'Invitation created successfully' . ($this->send_email ? ' and email sent' : '') . '.');
}
public function deleteUser(User $user)
@ -81,6 +82,24 @@ class ManageUsers extends Component
session()->flash('success', "User role updated to {$role}.");
}
public function deleteInvitation(Invitation $invitation)
{
$this->authorize('invite', User::class);
// Only allow deletion of pending invitations
if (!$invitation->isPending()) {
session()->flash('error', 'Cannot delete accepted invitations.');
return;
}
$invitation->delete();
// Refresh the data
$this->invitations = Invitation::orderBy('accepted_at', 'desc')->get();
session()->flash('success', 'Invitation deleted successfully.');
}
public function render()
{
return view('livewire.manage-users');

View File

@ -3,6 +3,7 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Invitation extends Model
{
@ -28,6 +29,11 @@ class Invitation extends Model
$this->save();
}
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'invited_by', 'id');
}
public function getInviteUrl(): string
{
return route('register', ['code' => $this->code]);

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@ -13,6 +14,7 @@
margin: 0;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
@ -21,20 +23,24 @@
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px 20px;
text-align: center;
}
.header h1 {
margin: 0;
font-size: 28px;
font-weight: 600;
}
.content {
padding: 30px 20px;
}
.button {
display: inline-block;
background: #667eea;
@ -45,9 +51,11 @@
font-weight: 500;
margin: 20px 0;
}
.button:hover {
background: #5a6fd8;
}
.footer {
background: #f8f9fa;
padding: 20px;
@ -55,6 +63,7 @@
color: #6c757d;
font-size: 14px;
}
.invite-details {
background: #f8f9fa;
border-radius: 6px;
@ -63,43 +72,48 @@
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>= AuthentiKate</h1>
<p>You've been invited to join our authentication platform</p>
</div>
<div class="content">
<h2>Hello!</h2>
<p>You've been invited to create an account on <strong>AuthentiKate</strong>, our secure authentication platform. This will give you access to various applications and services.</p>
<p>You've been invited to create an account on <strong>AuthentiKate</strong>, our secure authentication
platform. This will give you access to various applications and services.</p>
<div class="invite-details">
<h3>Invitation Details:</h3>
<p><strong>Email:</strong> {{ $invitation->email }}</p>
<p><strong>Invited by:</strong> Admin</p>
<p><strong>Invited by:</strong> {{ $invitation->creator->name }}</p>
<p><strong>Expires:</strong> {{ $invitation->expires_at->format('F j, Y \a\t g:i A') }}</p>
</div>
<p>To accept this invitation and create your account, click the button below:</p>
<div style="text-align: center;">
<a href="{{ $invitation->getInviteUrl() }}" class="button">Accept Invitation</a>
</div>
<p>Or copy and paste this link into your browser:</p>
<p style="word-break: break-all; background: #f8f9fa; padding: 10px; border-radius: 4px; font-family: monospace;">
<p
style="word-break: break-all; background: #f8f9fa; padding: 10px; border-radius: 4px; font-family: monospace;">
{{ $invitation->getInviteUrl() }}
</p>
<p><strong>Note:</strong> 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.</p>
<p><strong>Note:</strong> 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.</p>
</div>
<div class="footer">
<p>This invitation was sent from AuthentiKate.</p>
<p>If you weren't expecting this invitation, you can safely ignore this email.</p>
</div>
</div>
</body>
</html>

View File

@ -67,8 +67,11 @@
<flux:badge>{{$inv->status}}</flux:badge>
@endswitch
</div>
<div class="flex gap-4 items-center">
<div class="flex gap-2 items-center">
<flux:button variant="primary" size="sm">Copy invite link</flux:button>
@if($inv->isPending())
<flux:button variant="danger" size="sm" icon="trash" wire:click="deleteInvitation({{ $inv->id }})" />
@endif
</div>
</x-card>
@endforeach