{"id":19482907,"url":"https://github.com/rafaelblum/todo-list","last_synced_at":"2026-04-15T19:39:29.873Z","repository":{"id":189514741,"uuid":"679040727","full_name":"RafaelBlum/Todo-list","owner":"RafaelBlum","description":"Aplicação Laravel de criação de atividades, utilizando a \"extensão\" Livewire 2.0. Uma extensão reativa, que agiliza o desenvolvimento com componentes reativo \"sem\" o uso de javascript (Existe o javascript, mas não precisamos se preocupar com desenvolvimento). Uso no frontend das bibliotecas Tailwindcss, Alpinesjs e RemixIcon.","archived":false,"fork":false,"pushed_at":"2023-09-05T14:24:19.000Z","size":14560,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-08T07:28:32.664Z","etag":null,"topics":["alpinesjs","authorization","blade","componentes","laravel","livewire","php","policy","remixicon","tailwindcss"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RafaelBlum.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-16T01:15:29.000Z","updated_at":"2023-10-29T01:06:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"ae8d8584-2595-4d5b-b960-85bf40272080","html_url":"https://github.com/RafaelBlum/Todo-list","commit_stats":null,"previous_names":["rafaelblum/todo-list"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RafaelBlum%2FTodo-list","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RafaelBlum%2FTodo-list/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RafaelBlum%2FTodo-list/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RafaelBlum%2FTodo-list/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RafaelBlum","download_url":"https://codeload.github.com/RafaelBlum/Todo-list/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240718873,"owners_count":19846481,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alpinesjs","authorization","blade","componentes","laravel","livewire","php","policy","remixicon","tailwindcss"],"created_at":"2024-11-10T20:12:36.563Z","updated_at":"2026-04-15T19:39:24.842Z","avatar_url":"https://github.com/RafaelBlum.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003ca href=\"https://laravel.com\" target=\"_blank\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg\" width=\"400\" alt=\"Laravel Logo\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"#\"  target=\"_blank\" title=\"calculadora com livewire\"\u003e\n\t\t\u003cimg src=\"public/images/gif-todo-3.gif\" alt=\"Todo list with livewire\" width=\"100%\"\u003e\n\t\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003cimg src=\"https://img.shields.io/badge/version project-2.0-brightgreen\" alt=\"version project todo\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Php-8.2-informational\u0026color=brightgreen\" alt=\"stack project\"\u003e\n    \u003cimg src=\"https://img.shields.io/static/v1?label=Laravel\u0026message=9.52.5\u0026color=brightgreen?style=for-the-badge\" alt=\"stack project\"\u003e\n    \u003cimg src=\"https://img.shields.io/static/v1?label=Livewire\u0026message=2.12\u0026color=brightgreen?style=for-the-badge\" alt=\"stack project\"\u003e\n\t\u003ca href=\"https://opensource.org/licenses/GPL-3.0\"\u003e\n\t\t\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"GPLv3 License\"\u003e\n\t\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/static/v1?label=Tailwindcss\u0026message=3.3.3\u0026color=brightgreen?style=for-the-badge\" alt=\"stack project\"\u003e\n    \u003cimg src=\"https://img.shields.io/static/v1?label=AlpineJs\u0026message=2.8.2\u0026color=brightgreen?style=for-the-badge\" alt=\"stack project\"\u003e\n    \u003cimg src=\"https://img.shields.io/static/v1?label=Remixicon\u0026message=2.5.0\u0026color=brightgreen?style=for-the-badge\" alt=\"stack project\"\u003e\n\u003c/p\u003e\n\n## Projeto Todo task v.2.0\nEste é uma `aplicação Laravel` utilizando a \"extensão\" `Livewire`. Uma extensão reativa, que agiliza o desenvolvimento\ncom `componentes reativo` \"sem\" o uso de javascript (Existe o javascript, mas não precisamos se preocupar com  desenvolvimento).\n\n\u003e Com **livewire** temos componentes responsivos e juntamente com o blade, temos uma ferramenta poderosa. Componentes que podemos atualizar sem\n\u003eprecisar atualizar toda página de forma fácil e rápida.\n\n##### Descrição de funcionalidades do `app task`\n- **listagem de todas atividades** _Criação de compoenente `todo` e busca de atividades por `query` e `when` para filtro_ e messagem de listagem vazia caso não tenha.\n- **Filtro das atividades por `pendentes` e `concluídas`** _Criação de propriedade `filter` com status `all, pending, done` para query `when`_.\n- **Ordenação da listagem** _Utilização de `orderBy` por `checked` de atividades_.\n- **`Check` com input da atividade concluída** _Criação de input do typo `checkbox` para concluir atividade com novo componente `item` com metodo updatedTodo da propriedade Propriedade `Todo $todo`_.\n- **Reoordenação da listagem ao check da atividade** _Utilização de `event` livewire no compoente `Item` que vai ao `salvar` fazer o `refresh` na listagem do component `Todo` pelo evento `emitTo e listeners`_.\n- **Creação de atividade** _A criação da atividade irá receber via `click` o titulo da atividade e refresh na lista `todo`_.\n- **Exclusão da atividade** _Uma deleção básica e refresh na lista `todo`_.\n- **No frontend:** _Layout responsivo e mode dark usando `Tailwindcss`_.\n\n\n##### Descrição de funcionalidades do `app task` para a versão `2.0`.\nNa versão 2.0 do app, além do `layout novo`, foi adicionado `propriedades computadas` do livewire, `autorizações` de usuários \npara suas atividades, `autenticação` básica de login/logout para demonstração do que um usuário pode visualizar e interagir no app e por \nfim `notificações` para cada ação.\n\n- **Autenticação de usuário** _Criação demonstrativa de usuário direto pelo id_.\n- **Politicas de Autenticação de usuário** _Usuários só podem criar, editar e deletar se estiverem logados_.\n- **Autorização de ações** _Usuário não pode visualizar a deleção da atividade se a atividade não foi criada por ele_.\n- **Negação de ações** _Usuário não pode editar atividade que não foi criada por ele_.\n- **Notificações** _Criar notificações na tela para ações_.\n- **Parametros da url** _Criar parametros nos filtro da URL para um histórico na navegação_.\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"#\"  target=\"_blank\" title=\"Diagrama\"\u003e\n\t\t\u003cimg src=\"public/images/diagram-2.jpg\" alt=\"Diagramação de componentes livewire\" style=\"border-radius: 5px;\" width=\"600\"\u003e\n\t\u003c/a\u003e\n\u003c/p\u003e\n\n######  Tecnologias (serviços externos, libs, frameworks, hospedagem etc.) e instalações.\n\n- \u003ca href=\"#\" target=\"_blank\"\u003ePhp `8.2`\u003c/a\u003e\n- \u003ca href=\"#\" target=\"_blank\"\u003eLaravel `9.52.5`\u003c/a\u003e [Projeto laravel] composer create-project laravel/laravel name-project\n- \u003ca href=\"#\" target=\"_blank\"\u003eLivewire `2.12`\u003c/a\u003e [Livewire] composer require livewire/livewire\n- \u003ca href=\"#\" target=\"_blank\"\u003elaravel debugbar `3.8`\u003c/a\u003e [Debugbar] composer require barryvdh/laravel-debugbar --dev\n- \u003ca href=\"#\" target=\"_blank\"\u003eRemixicon `2.5.0`\u003c/a\u003e [Docs](https://remixicon.com/)\n- \u003ca href=\"#\" target=\"_blank\"\u003eTailwindcss `3.3.3`\u003c/a\u003e [Tailwindcss] npm install -D tailwindcss postcss autoprefixer\n    - Configuração do framework esta neste link [Install Tailwind CSS with Laravel](https://tailwindcss.com/docs/guides/laravel)\n- \u003ca href=\"#\" target=\"_blank\"\u003eAlpine jS `2.8.2`\u003c/a\u003e [Docs](https://github.com/alpinejs/alpine/tree/v2.8.2)\n\n## Desenvolvimento (backend lógica e comandos)\n- `php artisan serve --port=8000` [inicializando servidor] \n- `php artisan livewire:make todo ` [Criando componente todo] \n- `php artisan make:model Todo -m ` [Criado a tabela modelo para add propriedades] \n    - checked **boolean** _nullable false_\n    - title **string**\n- `php artisan make:factory TodoFactory --model=Todo ` [Criado a migration para tabela no banco] \n    - checked =\u003e **$this-\u003efaker-\u003e_boolean_**\n    - title =\u003e **$this-\u003efaker-\u003e_sentence_**\n- `php artisan migrate --seed ` [Criado a migration de todas tabelas no banco e seed populando dados fakes] \n- **Criação do componentes de interação**: _A ideia é trabalhar com cada `componente livewire` de modo separado e não no proprio componente `todo`, para assim não ter um componente com muitas responsabilidades e desta forma cada componente tera a sua._\n    - `php artisan livewire:make todo.item ` [Criando componente todo item] | _Componente que terá a responsabilidade de realizar o checked da atividade_.\n    - `php artisan livewire:make todo.create ` [Criando componente todo create] | _Componente que terá a responsabilidade de criar componente com seu titulo_.\n    - `php artisan livewire:make todo.delete ` [Criando componente todo delete] | _Componente que terá a responsabilidade de deletar a tividade_.\n\n    \n## Desenvolvimento (Frontend layout e lógica)\n\n`View blade *todo*` - listagem \n~~~~~~view\n{{-- LIST TASKS --}}\n@if(count($todos) \u003e 0)\n    @foreach($todos as $todo)\n        \u003clivewire:todo.item :todo=\"$todo\" :key=\"$todo-\u003eid\" /\u003e\n    @endforeach\n@else\n    \u003cdiv class=\"flex justify-center rounded-lg font-medium tracking-wide text-red-500 text-xs mt-6 mb-6\"\u003e\n        \u003cdiv\u003e\n            Não existem tarefas registradas!\n        \u003c/div\u003e\n    \u003c/div\u003e\n@endif\n~~~~~~\n\n| Diretiva | Explicação |\n| :---         |     :---      |\n| `@foreach($todos as $todo)` | *Recebendo a listagem com todas atividades ou por filtro no componente `todo` com um foreach para mostrar cada um.* |\n| `\u003clivewire:todo.item :todo=\"$todo\" :key=\"$todo-\u003eid\" /\u003e` | *Passando cada atividade para `componente view item` e para que cada tenha sua identificação para livewire, passamos o `key` do `ID`.* |\n\n######  Exemplo 1\n\n`View blade *create*` - Como passar dados de input para metodo com click `Enter`.\n~~~~~~\n\u003cinput wire:model.defer=\"title\" wire:keydown.enter=\"save\"\n~~~~~~\n\n\n`Controller *create*`\n~~~~~~Create\n    public string $title ='';\n\n    public function save()\n    {\n        $this-\u003evalidate(['title' =\u003e ['required', 'min:3']],\n            [\n                'title.required' =\u003e 'Descrição é obrigatória!',\n                'title.min'=\u003e 'Mínimo de 3 letras, por favor!'\n            ]);\n\n        Todo::create(['title' =\u003e $this-\u003etitle]);\n        $this-\u003ereset('title');\n        $this-\u003eemitTo(\\App\\Http\\Livewire\\Todo::class, 'todo::created');\n    }\n~~~~~~\n\n`Controller *Todo*`\n~~~~~~Create\nprotected $listeners = [\n        'todo::updated' =\u003e '$refresh',\n        'todo::created' =\u003e '$refresh',\n        'todo::deleted' =\u003e '$refresh'\n];\n~~~~~~\n\n| Classe | Explicação importantes |\n| :---         |     :---      |\n| `validate(['title' =\u003e ['required', 'min:3']]` | * Validação de criação e mensagens personalizadas de cada tipo* |\n| `$this-\u003eemitTo` | *EmitTo é uma função que avisa um componente de alguma atividade realizada e apartir disso podemos por exemplo, realizar `refresh`* |\n\n\n\n## Desenvolvimento para versão 2.0\n- Estruturação de `migrate` e `model` da Todo.\n    - Adição da foreignId `$table-\u003eforeignIdFor(\\App\\Models\\User::class)-\u003enullable();`\n    - Adição da fillable user id `protected $fillable = ['title', 'checked', 'user_id']`\n    - Metodo belongsTo da Todo pegar o usuário dono.\n~~~~~~belongsTo\n    public function user(){\n        return $this-\u003ebelongsTo(User::class);\n    }\n~~~~~~    \n    \n- Criação de `factories e seeders` para popular banco.\n    - Exemplo\n~~~~~~public function run()\n    User::updateOrCreate([\n        'name'=\u003e 'Rafael Blum',\n        'email'=\u003e 'Rafaelblum_digital@hotmail.com',\n        'email_verified_at' =\u003e now(),\n        'password'=\u003e Hash::make('123'),\n        'remember_token' =\u003e Str::random(10),\n    ]);\n\n\n    User::updateOrCreate([\n        'name' =\u003e fake()-\u003ename(),\n        'email' =\u003e fake()-\u003eunique()-\u003esafeEmail(),\n        'email_verified_at' =\u003e now(),\n        'password' =\u003e '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password\n        'remember_token' =\u003e Str::random(10),\n    ]);\n\n    Todo::updateOrCreate([\n        'checked' =\u003e fake()-\u003eboolean,\n        'user_id' =\u003e User::where('email', 'Rafaelblum_digital@hotmail.com')-\u003efirst()-\u003eid,\n        'title' =\u003e fake()-\u003esentence\n    ]);\n~~~~~~    \n\n- Criação de politica todo.\n    - `php artisan make:policy TodoPolicy --model=Todo ` [Criando politica] | _Cria a policy e com o `--model=Todo` cria todos metodos_.\n    \n- A criação de `notificações` seram acessados direto pelo componente que irá `iniciar um evento` e assendo as props de componente do blade.\n~~~~~~componente livewire\n    $this-\u003eemit('notifications', [\n        'type'      =\u003e 'error',\n        'message'   =\u003e 'Você precisa se logar para criar atividade'\n    ]);\n~~~~~~\n- Metodo da classe Notifications\n~~~~~~componente livewire\n    protected $listeners = ['notifications'=\u003e'notify'];\n\n    public function notify($props)\n    {\n        $this-\u003emessage = $props['message'];\n        $this-\u003etype = $props['type'];\n    }\n~~~~~~\n- view livewire e componente x-blade\n~~~~~~componente livewire\n\u003cx-notification :type=\"$type\"\u003e\n    {!! $message !!}\n\u003c/x-notification\u003e\n\n~~~~~~\n\n~~~~~~componente blade e props\n@props([\n    'type'\n])\n\n\n\u003cdiv {{$attributes-\u003eclass([\n    'w-80 text-center text-sm mb-2 font-semibold tracking-wide cursor-pointer',\n    'text-yellow-500' =\u003e $type == 'warning',\n    'text-red-500' =\u003e $type == 'error',\n    'text-green-500' =\u003e $type == 'success',\n    'text-indigo-500' =\u003e $type == 'info',\n])}} \u003e\n    {{$slot}}\n\u003c/div\u003e\n~~~~~~\n\n- Autorizações de ações. \n    - Atraves da Politica criada da todo, cada metodo ira retornar e verificar se o user id do user logado é igual ao id do user_id da tabela Todo.\n    - `return $user-\u003eis($todo-\u003euser);` \n    - Na classe Delete, por exemplo.\n    \n~~~~~~AuthorizesRequests;\n    use Illuminate\\Foundation\\Auth\\Access\\AuthorizesRequests;\n    use AuthorizesRequests;\n    $this-\u003eauthorize('delete', $this-\u003etodo);\n~~~~~~\n\n- Outra forma de autorização é utilizando o `can()`\n\n~~~~~~can()\n    if(!auth()-\u003echeck() || !auth()-\u003euser()-\u003ecan('update', $this-\u003etodo)){\n        $this-\u003eemit('notifications', [\n            'type'      =\u003e \"error\",\n            'message'   =\u003e \"Você não pode finalizar a atividade \u003cbr\u003e {$this-\u003etodo-\u003etitle}\"\n        ]);\n\n        return;\n    }\n~~~~~~\n\n- Nas views podemos também usar o @can()\n    - Aqui se não é sua atividade, você não terá acesso a visualização do componente.\n~~~~~~can()\n    @can('update', $todo)\n        ...\n    @endcan\n~~~~~~\n\n\n## Contatos\n\n- 👇🏼 [rafaelblum_digital@hotmail.com]\n\n[![Youtube Badge](https://img.shields.io/badge/-Youtube-FF0000?style=flat-square\u0026labelColor=FF0000\u0026logo=youtube\u0026logoColor=white\u0026link=https://www.youtube.com/channel/UCMvtn8HZ12Ud-sdkY5KzTog)](https://www.youtube.com/channel/UCMvtn8HZ12Ud-sdkY5KzTog)\n[![Instagram Badge](https://img.shields.io/badge/-rafablum_-violet?style=flat-square\u0026logo=Instagram\u0026logoColor=white\u0026link=https://www.instagram.com/rafablum_/)](https://www.instagram.com/rafablum_/)\n[![Twitter: universoCode](https://img.shields.io/twitter/follow/universoCode?style=social)](https://twitter.com/universoCode)\n[![Linkedin: RafaelBlum](https://img.shields.io/badge/-RafaelBlum-blue?style=flat-square\u0026logo=Linkedin\u0026logoColor=white\u0026link=https://www.linkedin.com/in/rafael-blum-378656285/)](https://www.linkedin.com/in/rafael-blum-378656285/)\n[![GitHub RafaelBlum](https://img.shields.io/github/followers/RafaelBlum?label=follow\u0026style=social)](https://github.com/RafaelBlum)\n\n\n\u003cimg src=\"https://media.giphy.com/media/LnQjpWaON8nhr21vNW/giphy.gif\" width=\"60\"\u003e \n    \u003cem\u003e\u003cb\u003eAdoro me conectar com pessoas diferentes,\u003c/b\u003e então se você quiser dizer \u003cb\u003eoi, ficarei feliz em conhecê-lo mais!\u003c/b\u003e :)\u003c/em\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frafaelblum%2Ftodo-list","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frafaelblum%2Ftodo-list","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frafaelblum%2Ftodo-list/lists"}