Posts
To proceed with notifications, we need events that trigger them. We will notify a user whenever they are tagged in a post. So let's move on to creating the posts.
New posts
Let's add an option to register posts to our navbar:
In resources/views/livewire/layout/navigation.blade.php:
<x-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.index')" wire:navigate>
{{ __('Posts') }}
</x-nav-link>
<x-responsive-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.index')" wire:navigate>
{{ __('Posts') }}
</x-responsive-nav-link>
Using Laravel commands we can create several resources at the same time.
For more details: https://laravel.com/docs/10.x/eloquent#generating-model-classes
In our case we will create the Model, migration and controller with resources:
php artisan make:model -mrc Post
In database/migrations/{date}_create_posts_table.php:
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->foreignId('tagged_user_id')->nullable()->constrained('users')->cascadeOnDelete();
$table->string('message', 280);
$table->timestamps();
});
}
tagged_user_id can be null, since a post can be created without having to tag someone.
Let's run the migrations:
php artisan migrate
Route::view('posts','posts.index')->middleware('auth')->name('posts.index');
protected $fillable = [
'user_id',
'tagged_user_id',
'message',
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function taggedUser(): BelongsTo
{
return $this->belongsTo(User::class, 'tagged_user_id');
}
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
public function taggedPosts(): HasMany
{
return $this->hasMany(Post::class, 'tagged_user_id');
}
Let’s create the post registration and listing components:
php artisan make:livewire posts.post-create
php artisan make:livewire posts.post-list
Let's create the index.blade.php file in resources/views/posts, and import the default layout with our components:
<x-app-layout>
@livewire('posts.post-create')
@livewire('posts.post-list')
</x-app-layout>
One point of attention: To make the project simpler, we will not work with validation and repository layers.
In resources/views/livewire/posts/post-create.blade.php:
<div>
<form class="grid grid-cols-2 max-w-xl mx-auto m-6" wire:submit.prevent="save">
<textarea
wire:model="state.message"
placeholder="{{ __('Post Message') }}"
class="col-span-2 w-full shadow rounded-lg border-gray-200"
></textarea>
@error('state.message') <span class="error">{{ $message }}</span> @enderror
<select wire:model="state.tagged_user_id" class="mt-4 border-gray-200 rounded-lg">
<option value=""></option>
@foreach($users as $user)
<option value="{{$user->id}}">{{$user->name}}</option>
@endforeach
</select>
@error('state.tagged_user_id') <span class="error">{{ $message }}</span> @enderror
<div class="flex justify-end">
<button class="w-16 rounded-lg mt-4 bg-blue-500 shadow text-white">{{ __('Save') }}</button>
</div>
</form>
</div>
Let's add it to app/Livewire/Posts/PostCreate.php:
public $state = [
'tagged_user_id' => null,
'message' => ''
];
public $users = null;
public function mount()
{
$this->users = User::query()->get();
}
public function save(Request $request)
{
$this->validate([
'state.message' => 'required|max:280',
'state.tagged_user_id' => 'sometimes'
]);
$request->user()->posts()->create($this->state);
$this->reset('state');
}
List of posts
Now, we will proceed with the list of posts, where we will include both the posts we created and those in which we were tagged.
In resources/views/livewire/post/post-list.blade.php:
<div>
<div class="max-w-xl mx-auto mt-16">
@foreach($posts as $post)
<div class="bg-white p-6 rounded-md shadow-md text-center break-words mt-4">
<p class="text-gray-700">
"{{$post->message}}"
</p>
<p class="text-blue-500 text-sm">{{ optional($post->taggedUser)->name ? '@'.$post->taggedUser->name : '' }}</p>
<p class="text-end text-sm text-gray-500 mt-2">{{$post->user->name}}</p>
</div>
@endforeach
</div>
</div>
In app/Livewire/Posts/PostList.php:
<?php
namespace App\Livewire\Posts;
use Livewire\Component;
class PostList extends Component
{
public $posts;
public function render()
{
$this->posts = auth()->user()->posts()
->orWhere('tagged_user_id', auth()->user()->id)
->orderBy('id', 'desc')
->get();
return view('livewire.posts.post-list');
}
}
Reactivity
When a post is created, you need to reload the screen to view it. However, with Livewire, we were able to make the listing reactive. This means that when we create a post the list will be updated automatically.
But how?
Let's dispatch the creation component to the listing component, indicating that it is necessary to update the list.
In app/Livewire/Posts/PostCreate.php let's add dispatch:
$this->dispatch('refreshPostList');
In app/Livewire/Posts/PostList.php let's add our listener with the refresh event:
protected $listeners = [
'refreshPostList' => '$refresh'
];
Ready! Our features are now reactive.
Top comments (0)