Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/rafaelblum/livewire-v3-crud-uploading

Este é um projeto de desenvolvimento de CRUD, Uploading de imagens, bibliotecas front-end e backend, afim de desenvolver mais a nova versão do Livewire 3.0.
https://github.com/rafaelblum/livewire-v3-crud-uploading

chartjs crud flowbite graficos laravel layouts livewire tailwindcss upload-images

Last synced: 4 days ago
JSON representation

Este é um projeto de desenvolvimento de CRUD, Uploading de imagens, bibliotecas front-end e backend, afim de desenvolver mais a nova versão do Livewire 3.0.

Awesome Lists containing this project

README

        

Laravel Logo



Todo list with livewire


version project todo
stack project
stack project
stack project

GPLv3 License



stack project
stack project
stack project

# 🚀 [Livewire 3.0 - CRUD and uploading image](#)

### Objetivo do projeto

Demonstrar o poder do `livewire` na `versão 3.0` com a criação de `CRUD` de `produto`, `estudante` e `users`, juntamente com o `uploading de imagens`.
E inclui um `sorteio ramdomico` de estudantes, `graficos com chartJS`, e `adaptação de layout administrativo` para o projeto trabalhando as views
com partials, layouts e `skeletons de loadings`.



Livewire 3.0 - CRUD and uploading image

### Tecnologias (serviços externos, libs, frameworks, hospedagem etc.) e instalações.

- 🧩 Php `8.2`
- 🧩 Laravel `10.10` [Projeto laravel] composer create-project laravel/laravel name-project
- 🧩 Livewire `3.0` [Livewire] composer require livewire/livewire
- 🧩 laravel debugbar `3.8` [Debugbar] composer require barryvdh/laravel-debugbar --dev
- 🧩 Remixicon `2.5.0` [Docs](https://remixicon.com/)
- 🧩 Tailwindcss `3.3.3` [Install](https://tailwindcss.com/docs/guides/laravel) npm install -D tailwindcss postcss autoprefixer
- 🧩 Flowbite `1.8.1` [cdn Install](https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.8.1/flowbite.min.css)
- 🧩 ChartJS `4.4.0` [cdn Install](https://cdn.jsdelivr.net/npm/chart.js)

## :construction: Desenvolvimento das camadas de componentes
- `php artisan livewire:make gallery.create ` [Component's gallery Product]
- `php artisan livewire:make gallery.edit `
- `php artisan livewire:make gallery.index `
- `php artisan livewire:make student.create ` [Component's student Student]
- `php artisan livewire:make student.edit `
- `php artisan livewire:make student.index `
- `php artisan livewire:make users.create ` [Component's users Users]
- `php artisan livewire:make users.index `
- `php artisan livewire:make raffle.sortition ` [Component's raffle Sortition]
- `php artisan livewire:make adm.painel-button ` [Component's adm Painel-button]

## Descritivo dos modulos `components` e front-end

- :zap: Foi criada todas migrates, factories e seeders para popular o banco de dados.
- :zap: Criado um CRUD completo de produtos e upload de images de cada produto registrado, juntamente com as devidas validações de imagens, propriedades e front-end.
- :zap: Estudantes seguiu o mesmo desenvolvimento de CRUD e upload de produto.
- :zap: Foi personalizado a paginação de todos componentes.
- :zap: Foi criado um componente ADM para ser responsável pelos botões rapidos do painel ADM.
- :zap: Criado a listagem simples de usuários e formulário de criação de usuários.
- :zap: O frontend foi todo personalizado apartir de um `template ADM` usando o `Tailwind e Flowbite`.
- :zap: Criado uma página de sorteio aleatório de estudantes importando a biblioteca `JSConfetti`.

~~~~~~
import JSConfetti from 'js-confetti'

const jsConfetti = new JSConfetti();

window.confetti = ()=> jsConfetti.addConfetti(
{
emojis: ['🌈', '⚡️', '💥', '✨', '💫', '🌸', '👾', '🌞', '💯'],
}
);
~~~~~~

> Abaixo coloquei alguns exemplos simplificados sobre o projeto.

## :label: Exemplo de algumas `atividades` no desenvolvimento.

- :ok_hand: Implement Dependent Dropdown [Documentação](https://livewire.laravel.com/docs/lifecycle-hooks#update)
- updating é renderizado com todas propriedade que após forem atualizadas/selecionada, mas Updated atualização da `propriedade especifica`, no caso a `class_id`
~~~~~~method updated

#[Rule('required', message: 'Precisa selecionar uma disciplina.')]
public $class_id;

public $sections = [];

public function updatedClassId($value)
{
$this->sections = Section::where('class_id', $value)->get();
}
~~~~~~

> Na view
~~~~~~foreach sections

Selecione a turma
@foreach ($sections as $section)

{{ $section->name }} - {{ $section->class->name }}

@endforeach

~~~~~~

- :ok_hand: `STORAGE::` Exemplos com a classe Storage
~~~~~~
if(storage_path('app/public/'.$this->student->image)){
1.create a new folder
Storage::makeDirectory('testeImage');

2.store file in directory
Storage::putFile('testeImage', $this->image);

3.file generated name hash name
$generatedName = $this->image->hashName();
dd($generatedName);

4.store file in directory and rename
Storage::putFileAs('testeImage', $this->image, "student-".$this->student->id.".".$this->image->extension());

5.copy file to another directory
Storage::copy('testeImage/student-1.jpg', 'public/imageCopy.png');

6.cut file to another directory
Storage::move('public/imageCopy.png', 'public/testeImage/cutImage.png');

7.list files or sub files inside folder
$array[] = Storage::files('public/students');
$array[] = Storage::allFiles('public');
dd($array);

8.show files
$file = Storage::get('public/default.jpg');
//get file diretory and create to another diretory
dd(Storage::put('students/student-1.jpg', $file));

9.download file
return Storage::download('public/default.jpg');

10.delete file(s)
if(Storage::exists('students/student-1.jpg')){
dd(Storage::delete('students/student-1.jpg'));
}

if(Storage::directoryExists('students')){
dd("DIRETÓRIO EXCLUIDO!", Storage::deleteDirectory('students'));
}

dd('sem arquivo e diretório');

dd(Storage::disk('public'));

}
~~~~~~

- :ok_hand: DATA BIND
> Passando ID student via rota controller laravel. Poderiamos passar direto pelo component, direto na view sem layout
~~~~~~

~~~~~~

- :ok_hand: Como criar uma TAG com um valor inicial
> Na propria chamada do componente criamos um propriedade e definimos seu valor e na view a TAG já terá seu valor.

~~~~~~


{{-- IN VIEW COMPONENT --}}

~~~~~~

- :ok_hand: Como passar um valor de uma variável para view de um componente
> Exemplo criando uma variável, mas poderia receber de uma variável de um component.

~~~~~~


~~~~~~
> No controller temos que inicializar no metodo construtor do component `mount`

~~~~~~
public $git;

public function mount($git = null)
{
$this->git = $git;
}
~~~~~~

- :ok_hand: Actions
> Ações de botões e formulários que reagem com click de botão, form's chamado algum metodo.
~~~~~~
...
...
~~~~~~

- :ok_hand: Atualizar algum component modificado
> Exemplo que atualiza a tabela de usuários. Basta incluir na `div` do componente para o _liveiwre_ fazer a **poll** - `wire:poll.visible`

~~~~~~
...
~~~~~~

- :ok_hand: Data Binding
> É a forma que vamos interagir e definir valores as propriedades do nosso componente livewire. `wire:model="propertyName"` ou
> na nova versão 3.0 `wire:model.live="propertyName"`.

~~~~~~view component




~~~~~~

~~~~~~class component
class Create extends Component
{
public $name;

public function save(){
User::create([
'name' => $this->name,
]);
}
}
~~~~~~

- :ok_hand: Validation
> Na versão 2.0 do livewire seria assim a validação no metodo save.

~~~~~~
public function save(){
$this->validate(
[
'name' => 'required|min:3|max:200',
'email' => 'required|email|unique:users',
'password' => 'required|min:8'
],
[
'name.required' => 'Nome é obrigatório!',
'name.min' => 'O minimo para seu nome é 3 caracteres.',
'name.max' => 'O maximo para seu nome é de 200 caracteres',
'email.required' => 'Email é obrigatório!',
'email.unique' => 'Este e-mail já foi registrado!',
'password.required' => 'A senha é obrigatória!',
'password.min' => 'A senha deve ter no minimo 8 caracteres.',
]
);
}
~~~~~~

> Na versão 3.0 já ficou mais limpo e claro com as anotações.

~~~~~~Exemple
use Livewire\Attributes\Rule;

#[Rule(['name'=>'required|min:3'], message: ['required' => 'O :attribute é necessário.'], attribute: ['name' => 'nome'])]
public $name;

public function save(){
$this->validate()
...
}
~~~~~~

- :ok_hand: Flash Messages
> Passando messagem de retorno para front-end. Utilizando o `helper` `request() e session()` com flush que passamos `2 argumentos`.
> E também podemos **_redirecionar_ para outra rota**, juntamente com uma messagem with.

~~~~~~
request()->session()->flush('success', 'Usuário criado com sucesso!!');
return redirect(router('/...'))->with('success', 'Usuário criado com sucesso!');
~~~~~~

- :ok_hand: Paginação
> A paginação é bem parecida com a do laravel, só precisamos chamar na classe o `WithPagination`.

~~~~~~
use WithPagination;

public function render()
{
return view('livewire.users.users',
[
'users' => User::paginate(2)
]);
}
~~~~~~

> Na view
~~~~~~


  • {{$users->links()}}

  • ~~~~~~

    - :ok_hand: Loading files|states [Documents loading](https://livewire.laravel.com/docs/uploads)
    > Para trabalhar com loading de arquivos, primeiro add na classe `WithFileUploads` e com metodo de armazenar os arquivos `store`.

    ~~~~~~Class component
    use WithFileUploads;

    /**
    *@var TemporaryUploadedFile|mixed $image
    */
    #[Rule('required|max:1024', message: 'Image obrigatória ou o tamanho é maior que 1024MB.')]
    public $image;

    public function save()
    {
    $this->image->store('image');
    }
    ~~~~~~

    > Configuração completa na view. `Visualização temporaria`, `carregamento de progresso`.

    ~~~~~~View component
    {{-- IMAGE --}}

    Image

    {{-- INPUT IMAGE --}}

    @if($image)




    @endif




    baixando image...



    @error('image') {{ $message }} @enderror


    ~~~~~~

    - :ok_hand: Eventos [Documents events](https://livewire.laravel.com/docs/events)
    > O metodo `dispatch()` é responsável por fazer a comunicação entre as classes doscomponentes e fazer a atualização `update`.
    > O processo é realizado chamando o `dispatch` gerando um nome e passar dados adicionais com o evento passando os dados como segundo parâmetro

    ~~~~~~Classe User
    $user = User::create([// ... ]);
    $this->dispatch('user-created', $user);
    ~~~~~~

    ~~~~~~Classe List users
    use Livewire\Attributes\On;

    #[On('user-created')]
    public function updateList($user = null){ //.. }
    ~~~~~~

    - :ok_hand: Polling [Documents Polling](https://livewire.laravel.com/docs/wire-poll)
    > Uma alternativa para não criar este evento é trabalhar com `wire:poll`
    > Desta forma, qualquer atualização no componente será feito o refresh | `

    ...
    `.

    ~~~~~~

    @foreach($users as $user)
    // ...
    @endforeach

    ~~~~~~

    - :ok_hand: Lazy Loading [Documents Loading](https://livewire.laravel.com/docs/lazy) e animação de Loading Skeletons [Skeletons](https://delba.dev/blog/animated-loading-skeletons-with-tailwind)
    > O componente esqueleto pode ser usado como um indicador de `carregamento alternativo` ao controle giratório, `imitando` o conteúdo que será carregado.

    ~~~~~~
    public function mount()
    {
    sleep(2);
    }

    /**
    * https://livewire.laravel.com/docs/lazy
    */
    public function placeholder()
    {
    return <<<'HTML'


    lazy loading Carregando...


    HTML;
    }
    ~~~~~~

    ~~~~~~

    ~~~~~~

    - :ok_hand: Propriedades Computadas [Property computer](https://livewire.laravel.com/docs/computed-properties)
    > As propriedades computadas permitem acessar valores e armazená-los em cache para acesso futuro durante a solicitação

    ~~~~~~Class
    use Livewire\Attributes\Computed;

    #[Computed()]
    public function users()
    {
    return User::paginate(2);
    }
    ~~~~~~

    ~~~~~~View
    @foreach($this->users as $user)
    //..
    @endforeach
    ~~~~~~

    - :ok_hand: Criar Layout [Layout](https://livewire.laravel.com/docs/quickstart#create-a-template-layout)
    - [Tutorial](https://www.youtube.com/watch?v=SKxIXm-MOE4&list=PLqDySLfPKRn543NM_fTrJRdhjBgsogzSC&index=16&ab_channel=YeloCode)
    > o Livewire procurará automaticamente um arquivo de layout.

    ~~~~~~
    php artisan livewire:layout
    ~~~~~~

    ~~~~~~






    {{ $title ?? 'Page Title' }}


    {{ $slot }}


    ~~~~~~

    - :ok_hand: [Form Objects | ](https://livewire.laravel.com/docs/forms)
    > Os objetos de formulário permitem reutilizar a lógica do formulário entre os componentes e fornecem uma ótima maneira
    >de manter a classe do componente mais limpa, agrupando todo o código relacionado ao formulário em uma classe separada.

    ~~~~~~
    php artisan livewire:form PostForm
    ~~~~~~

    ~~~~~~
    // class form
    class PostForm extends Form
    {
    #[Rule('required|min:5')]
    public $title = '';

    #[Rule('required|min:5')]
    public $content = '';
    }

    //class createForm
    public PostForm $form;

    public function save()
    {
    $this->validate();

    Post::create(
    $this->form->all()
    );

    return $this->redirect('/posts');
    }

    //view
    {{$form->title}}
    ~~~~~~

    - :ok_hand: [URL Query Parameters | ](https://livewire.laravel.com/docs/url)
    >
    ~~~~~~
    #[Url(as: 'busca', keep: true, history: true)]
    public $search = '';
    ~~~~~~

    - :ok_hand: [Offline States | ]()
    > Para você pode notificar os usuários caso eles estejam offline `wire:offline`.

    ~~~~~~


    Voçê encontra-se offline! Por favor, tente esabelecer a conexão ou tenta mais tarde.

    ~~~~~~

    - :ok_hand: [Wire:navigate | ](https://livewire.laravel.com/docs/wire-navigate)
    >
    ~~~~~~
    Dashboard
    ~~~~~~

    - :ok_hand: [Lifecycle hooks | ](https://livewire.laravel.com/docs/lifecycle-hooks)
    > Ciclo de vida dos hooks que permitem executar código em pontos específicos durante o ciclo de vida de um componente.

    | Hook Method | Explicação |
    | :--- | :--- |
    | `mount()` | *É como se fosse o `__construct()` de uma classe. * _Chamado quando um componente é criado._ |
    | `hydrate()` | _Chamado quando um componente é reidratado no início de uma solicitação subsequente._|
    | `boot()` | *É um metodo que sempre é chamado sempre. * _Chamado no início de cada solicitação no backend. Tanto inicial quanto subsequente._|
    | `updating()` | _Chamado antes de atualizar uma propriedade de componente._|
    | `updated()` | _Chamado após atualizar uma propriedade._|
    | `rendering()` | _Chamado antes `render()` é chamado._|
    | `rendered()` | _Chamado depois `render()` é chamado._|
    | `dehydrate()` | _Chamado no final de cada solicitação de componente._|

    - :ok_hand: [Keyboard Shortcuts | ](https://livewire.laravel.com/docs/actions#listening-for-specific-keys)
    > Os keywords são eventos de ações para o usuário.
    ~~~~~~

    @csrf
    //...

    ~~~~~~

    - :ok_hand: [Magic Actions | ](https://livewire.laravel.com/docs/actions#magic-actions)
    > Livewire fornece um conjunto de ações "mágicas" que permitem executar tarefas comuns em seus componentes sem definir métodos personalizados.
    ~~~~~~
    //$parent
    //$set | Modiica uma propriedade.
    //$refresh | aciona uma nova renderização do seu componente
    //$toggle
    //$dispatch
    //$event

    //exemples
    Refresh
    Reset Set

    Sort {{ $sortAsc ? 'Descending' : 'Ascending' }}

    ~~~~~~

    ## Contatos

    - 👇🏼 [[email protected]]

    [![Youtube Badge](https://img.shields.io/badge/-Youtube-FF0000?style=flat-square&labelColor=FF0000&logo=youtube&logoColor=white&link=https://www.youtube.com/channel/UCMvtn8HZ12Ud-sdkY5KzTog)](https://www.youtube.com/channel/UCMvtn8HZ12Ud-sdkY5KzTog)
    [![Instagram Badge](https://img.shields.io/badge/-rafablum_-violet?style=flat-square&logo=Instagram&logoColor=white&link=https://www.instagram.com/rafablum_/)](https://www.instagram.com/rafablum_/)
    [![Twitter: universoCode](https://img.shields.io/twitter/follow/universoCode?style=social)](https://twitter.com/universoCode)
    [![Linkedin: RafaelBlum](https://img.shields.io/badge/-RafaelBlum-blue?style=flat-square&logo=Linkedin&logoColor=white&link=https://www.linkedin.com/in/rafael-blum-378656285/)](https://www.linkedin.com/in/rafael-blum-378656285/)
    [![GitHub RafaelBlum](https://img.shields.io/github/followers/RafaelBlum?label=follow&style=social)](https://github.com/RafaelBlum)


    Adoro me conectar com pessoas diferentes, então se você quiser dizer oi, ficarei feliz em conhecê-lo mais! :)