Criação, Listagem e Reatividade 📜
Tags: tutorial, programming, laravel, beginners
Published: 2023-12-26 22:33:18

## Posts
Para prosseguirmos com as notificações, precisamos de eventos que as acionem. Como mencionado anteriormente, notificaremos um usuário sempre que ele for marcado em um post. Portanto, avançaremos para a criação dos posts.

## Novos posts
Vamos adicionar a nossa navbar uma opção para o cadastro dos posts:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zaopjnel5to829ypmfvf.png)

Em resources/views/livewire/layout/navigation.blade.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i34agte2m42szukk9qvw.png)
``` php
<x-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.index')" wire:navigate>
    {{ __('Posts') }}
</x-nav-link>
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b0e6a4b91ys7625iscza.png)

``` php
<x-responsive-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.index')" wire:navigate>
    {{ __('Posts') }}
</x-responsive-nav-link>
```

Através dos comandos do Laravel podemos criar vários recursos ao mesmo tempo, para mais detalhes [https://laravel.com/docs/10.x/eloquent#generating-model-classes](https://laravel.com/docs/10.x/eloquent#generating-model-classes), no nosso caso vamos criar a Model, migration and controller with resources:
`php artisan make:model -mrc Post`

Em database/migrations/{date}_create_posts_table.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/su17p75j7kyfz5ta0gbc.png)

``` 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 pode ser nula, visto que, um post pode ser criado sem ter que marcar alguém.

Vamos rodar as migrations:
`php artisan migrate`

Em routes/web.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1bl59evnmaqmu7vmujh.png)

``` php
Route::view('posts','posts.index')->middleware('auth')->name('posts.index');
```

Em app/Models/Post.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dsmzoot28p9td07vgbdu.png)

``` php
    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');
    }
```


Em app/Models/User.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jehekdi7szjvqgz91jx5.png)
``` php
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }

    public function taggedPosts(): HasMany
    {
        return $this->hasMany(Post::class, 'tagged_user_id');
    }
```

Vamos criar os componentes de cadastro e listagem dos posts:
`php artisan make:livewire posts.post-create`
`php artisan make:livewire posts.post-list`

Vamos criar em resources/views/posts o arquivo index.blade.php, e importaremos o layout default com nossos componentes:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d9a2wpqqjijtmrmjs2kd.png)

``` php
<x-app-layout>
    @livewire('posts.post-create')
    @livewire('posts.post-list')
</x-app-layout>
```

**_Um ponto de atenção: Para tornar o projeto mais simples não trabalharemos com camadas de validação e repositório._**

Em resources/views/livewire/posts/post-create.blade.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kugipnja9f53v1kbjjjw.png)
``` 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>

```

Vamos adicionar em app/Livewire/Posts/PostCreate.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nuppw6prjl82due3j2d3.png)

``` 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');
    }
```

##Listagem dos posts
Agora, procederemos com a listagem dos posts, onde incluiremos tanto os posts que criamos quanto aqueles nos quais fomos marcados.

Em resources/views/livewire/post/post-list.blade.php:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f2ags5pc5tzvapycliwt.png)
``` 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>

```

Em app/Livewire/Posts/PostList.php:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rn6gc296ixq85i23qbt5.png)
``` 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');
    }
}
```

##Reatividade
Quando um post é criado, é necessário recarregar a tela para visualizá-lo. No entanto, com Livewire, conseguimos tornar a listagem reativa. Isso significa que ao criarmos um post, a lista será atualizada automaticamente.

Mas como?
Vamos realizar um dispatch do componente de criação para o componente de listagem, indicando que é necessário atualizar a lista.

Em app/Livewire/Posts/PostCreate.php vamos adicionar o dispatch:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydye8glxt1vabwdw9g5v.png)
``` php
        $this->dispatch('refreshPostList');
```

Em app/Livewire/Posts/PostList.php vamos adicionar nosso listener com o evento de refresh:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fm0gf7l2ofter8qhdx6e.png)
``` php
    protected $listeners = [
        'refreshPostList' => '$refresh'
    ];
```

Pronto! Nossas funcionalidades já estão reativas.