To create the invitation system, we need to save the invitations themselves in the database.
So, let's create a Model with Migration.
php artisan make:model Invitation -m
For the invitation, we need these fields:
database/migrations/xxx_create_invitations_table.php:
Schema::create('invitations', function (Blueprint $table) { $table->id(); $table->foreignId('tenant_id')->constrained(); $table->string('email'); $table->string('token'); $table->timestamp('accepted_at')->nullable(); $table->timestamps();});
app/Models/Invitation.php:
class Invitation extends Model{ protected $fillable = [ 'tenant_id', 'email', 'token', 'accepted_at', ];}
Next, we need a form on the user's page with one email input.
resources/views/users/index.blade.php:
<x-app-layout> <x-slot name="header"> <h2 class="font-semibold text-xl text-gray-800 leading-tight"> {{ __('Users') }} </h2> </x-slot> <div class="py-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <div class="p-6 bg-white border-b border-gray-200"> Coming soon. <form method="POST" action="{{ route('users.store') }}"> @csrf <!-- Email Address --> <div class="mt-4"> <x-input-label for="email" :value="__('Email')" /> <x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autocomplete="username" /> <x-input-error :messages="$errors->get('email')" class="mt-2" /> </div> <div class="mt-4"> <x-primary-button> {{ __('Send Invitation') }} </x-primary-button> </div> </form> </div> </div> </div> </div></x-app-layout>
The form submission will lead to the store()
method in the UserController
. We will need validation, and we will use a Form Request.
php artisan make:request StoreUserRequest
app/Http/Requests/StoreUserRequest.php:
class StoreUserRequest extends FormRequest{ public function authorize(): bool { return true; } public function rules(): array { return [ 'email' => ['required', 'unique:invitations,email'], ]; }}
For now, we will create the invitation in the Controller and redirect it back to the users list page.
app/Http/Controllers/UserController.php:
use App\Models\Invitation;use Illuminate\Support\Str;use Illuminate\Contracts\View\View;use Illuminate\Http\RedirectResponse;use App\Http\Requests\StoreUserRequest; class UserController extends Controller{ public function index(): View { return view('users.index'); } public function store(StoreUserRequest $request): RedirectResponse { $invitation = Invitation::create([ 'tenant_id' => auth()->user()->current_tenant_id, 'email' => $request->input('email'), 'token' => Str::random(32), ]); return redirect()->route('users.index'); } }
We have a record in the database after entering some email in the invitation form and sending the invitation.
And finally, let's show all the invitations. First, in the Controller, we must pass the invitations on to the View.
app/Http/Controllers/UserController.php:
class UserController extends Controller{ public function index(): View { $invitations = Invitation::where('tenant_id', auth()->user()->current_tenant_id)->latest()->get(); return view('users.index'); return view('users.index', compact('invitations')); } // ...}
resources/views/users/index.blade.php:
// ... <div class="border-b border-gray-200 bg-white p-6"> <form method="POST" action="{{ route('users.store') }}"> @csrf <!-- Email Address --> <div class="mt-4"> <x-input-label for="email" :value="__('Email')" /> <x-text-input id="email" class="mt-1 block w-full" type="email" name="email" :value="old('email')" required autocomplete="username" /> <x-input-error :messages="$errors->get('email')" class="mt-2" /> </div> <div class="mt-4"> <x-primary-button> {{ __('Send Invitation') }} </x-primary-button> </div> </form> <table class="mt-8 w-full text-left text-sm text-gray-500"> <thead class="bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700"> <th scope="col" class="px-6 py-3 text-left">{{ __('Email') }}</th> <th scope="col" class="px-6 py-3 text-left">{{ __('Sent on') }}</th> </thead> <tbody> @foreach ($invitations as $invitation) <tr class="border-b bg-white dark:bg-gray-800"> <td class="px-6 py-4 font-medium text-gray-900whitespace-nowrap"> {{ $invitation->email }} </td> <td class="px-6 py-4 font-medium text-gray-900whitespace-nowrap"> {{ $invitation->created_at }} </td> </tr> @endforeach </tbody> </table> </div> // ...