Compare commits

..

11 Commits

Author SHA1 Message Date
lukidev 0518c06ebe
fix|feat: Ajusta componentes de formulários e inicia a construção do componente de mostrar usuários cadastrados, além de ajuste no Gate e nas permissões.
fix|feat: Ajusta componentes de formulários e inicia a construção do componente de mostrar usuários cadastrados, além de ajuste no Gate e nas permissões.
2025-11-10 22:53:25 -03:00
lukibeg 0aae934dd4 fix: Ajusta dashboard.blade.php 2025-11-10 22:20:40 -03:00
lukibeg 58453d316f feat: Implementa nova logo para o Nexus. 2025-11-10 22:19:04 -03:00
lukibeg da91153143 feat: Inicia construção do componente para exibir usuarios cadastrados no sistema. 2025-11-10 22:15:18 -03:00
lukibeg f489c6f751 fix: Altera campo de permissão para 'permissions' e linka com o componente de controller. 2025-11-10 22:07:19 -03:00
lukibeg 36c2ccae2f fix: Altera a ordem do dropdown e aplica melhorias visuais. 2025-11-10 22:06:10 -03:00
lukibeg 5275620b8d fix|feat: Aprimora visual(css) do header. 2025-11-10 22:02:47 -03:00
lukibeg b5d14206c8 feat: Inicia a construção do seeder de clientes. 2025-11-10 22:01:50 -03:00
lukibeg 7d867f1140 fix: Ajusta lógica do Gate e verificando se o user é admin ou não. 2025-11-10 22:01:15 -03:00
lukibeg 05c2d193e2 fix: Ajusta incluindo 'permissions' no array fillable. 2025-11-10 22:00:20 -03:00
lukibeg dbc8de4ede feat|fix: Constrói um componente de controller para exibição de usuários e ajusta alguns detalhes dos demais componentes de controller. 2025-11-10 21:59:33 -03:00
13 changed files with 72 additions and 92 deletions

View File

@ -3,53 +3,43 @@
namespace App\Livewire\Admin; namespace App\Livewire\Admin;
use App\Models\Client; use App\Models\Client;
use App\Services\ClientService;
use App\Livewire\Forms\ClientForm; // 1. Importa seu Form Object use App\Livewire\Forms\ClientForm; // 1. Importa seu Form Object
use Livewire\Component; use Livewire\Component;
use Livewire\WithFileUploads; use Livewire\WithFileUploads;
use Livewire\Attributes\On; use Illuminate\Support\Facades\Crypt;
class AddClient extends Component class AddClient extends Component
{ {
use WithFileUploads; use WithFileUploads;
// 1. Declara as propriedades principais
public ClientForm $form; public ClientForm $form;
/** public function save(ClientService $clientService)
* Método principal chamado pelo wire:submit="save".
*/
public function save()
{ {
// 2. Valida os dados usando as 'rules' do ClientForm.php
$this->form->validate(); $this->form->validate();
try { try {
$data = $this->form->all(); $data = $this->form->all();
$data['name'] = $data['client_name']; $data['name'] = $data['client_name'];
// 4. Lida com o upload do arquivo de imagem
if ($this->form->profile_image_path) { if ($this->form->profile_image_path) {
$path = $this->form->profile_image_path->store('client_logos', 'public'); $path = $this->form->profile_image_path->store('client_logos', 'public');
$data['profile_image_path'] = $path; $data['profile_image_path'] = $path;
} }
// 5. Cria o cliente no banco de dados $data['root_password'] = Crypt::encryptString($data['root_password']);
Client::create($data);
// 6. Despacha um evento para atualizar outros componentes (ex: o grid de clientes) $clientService->addClient($data);
$this->dispatch('client-added'); $this->dispatch('client-added');
// (Opcional) Envia uma notificação de sucesso
$this->dispatch('notify', message: 'Cliente adicionado com sucesso!'); $this->dispatch('notify', message: 'Cliente adicionado com sucesso!');
} catch (\Exception $e) { } catch (\Exception $e) {
dd($e);
$this->dispatch('notify', message: 'Ocorreu um erro inesperado ao salvar.', type: 'error'); $this->dispatch('notify', message: 'Ocorreu um erro inesperado ao salvar.', type: 'error');
} }
// 3. Pega todos os dados validados
} }
/**
* Renderiza a view do modal.
*/
public function render() public function render()
{ {
return view('livewire.admin.add-client'); return view('livewire.admin.add-client');

View File

@ -2,27 +2,24 @@
namespace App\Livewire\Admin; namespace App\Livewire\Admin;
use App\Services\UserService; // <-- Importe seu Service use App\Services\UserService;
use Illuminate\Support\Facades\Auth;
use Livewire\Component; use Livewire\Component;
class CreateUser extends Component class CreateUser extends Component
{ {
// 1. Propriedades públicas (os campos do formulário)
// Elas substituem o 'Request $request'
public string $name = ''; public string $name = '';
public string $email = ''; public string $email = '';
public string $password = ''; public string $password = '';
public string $password_confirm = ''; // <-- Você também precisa deste public string $password_confirm = '';
public bool $permission_level = false; public bool $permissions = false;
// 2. As regras de validação (copiadas do seu controller)
// Nota: Adicionei 'same:password' para garantir que as senhas batem.
protected $rules = [ protected $rules = [
'name' => 'required|string|max:255', 'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email', 'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8', 'password' => 'required|string|min:8',
'password_confirm' => 'required|string|same:password', // <-- Regra importante! 'password_confirm' => 'required|string|same:password',
'permission_level' => 'required|boolean' // ou 'required|in:0,1' 'permissions' => 'required|boolean'
]; ];
protected $messages = [ protected $messages = [
@ -31,48 +28,32 @@ class CreateUser extends Component
'email.unique' => 'O email informado já foi cadastrado anteriormente.', 'email.unique' => 'O email informado já foi cadastrado anteriormente.',
'password' => 'A senha precisa ter 8 ou mais caracteres.', 'password' => 'A senha precisa ter 8 ou mais caracteres.',
'password_confirm' => 'As senhas não coincidem.', 'password_confirm' => 'As senhas não coincidem.',
'permission_level' => 'Defina o nível de autorização do usuário.' 'permissions' => 'Defina o nível de autorização do usuário.',
]; ];
/**
* O método de "salvar", que substitui o seu 'createUsers'.
*
* Note como injetamos o UserService direto no método!
* O Livewire cuida disso para você, assim como o Laravel faz nos controllers.
*/
public function createUser(UserService $userService) public function createUser(UserService $userService)
{ {
// 3. Valida as propriedades públicas ($this->name, $this->email, etc.)
$validated = $this->validate($this->rules, $this->messages); $validated = $this->validate($this->rules, $this->messages);
// 4. Seu 'try...catch' - praticamente idêntico
if ($validated['permissions'] === true) {
$validated['permissions'] = array('admin');
} else {
$validated['permissions'] = array('user');
}
try { try {
// 5. CHAMA O MESMO SERVICE! Nenhuma lógica de negócio é duplicada. $this->authorize('createUser', Auth::user());
$user = $userService->createUser($validated); $user = $userService->createUser($validated);
// 6. O "Sucesso" (Tradução do Redirect)
// Limpa o formulário
$this->reset(); $this->reset();
// Dispara um evento para o Alpine.js fechar o modal
$this->dispatch('user-created'); $this->dispatch('user-created');
// Envia a mesma mensagem de sucesso do seu controller
$this->dispatch('notify', message: 'Usuário cadastrado com sucesso!'); $this->dispatch('notify', message: 'Usuário cadastrado com sucesso!');
// (Opcional) Se sua tabela de usuários for outro componente Livewire,
// você pode mandar ela atualizar assim:
// $this->dispatch('refreshUserList');
} catch (\Exception $e) { } catch (\Exception $e) {
// 7. O "Erro" (Tradução do Redirect de Erro)
// Em vez de redirecionar, adicionamos o erro ao formulário
// para que o usuário veja na tela, sem refresh.
$this->addError('general', $e->getMessage()); $this->addError('general', $e->getMessage());
} }
} }

View File

@ -0,0 +1,13 @@
<?php
namespace App\Livewire\Admin;
use Livewire\Component;
class ShowUsers extends Component
{
public function render()
{
return view('livewire.admin.show-users');
}
}

View File

@ -21,6 +21,7 @@ class User extends Authenticatable
protected $fillable = [ protected $fillable = [
'name', 'name',
'email', 'email',
'permissions',
'password', 'password',
]; ];

View File

@ -23,7 +23,7 @@ public function register(): void
public function boot(): void public function boot(): void
{ {
Gate::define('createUser', function (User $user) { Gate::define('createUser', function (User $user) {
return $user->permissions; return isset($user->permissions) ? in_array('admin', $user->permissions) : false;
}); });
} }
} }

View File

@ -3,6 +3,7 @@
namespace Database\Seeders; namespace Database\Seeders;
use App\Models\User; use App\Models\User;
use App\Models\Client;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents; // use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
@ -20,5 +21,7 @@ public function run(): void
'email' => 'inglinesystemsadmin@inglinesystems.com.br', 'email' => 'inglinesystemsadmin@inglinesystems.com.br',
'password' => Hash::make('*Ingline.Sys#9420%SECURITY#') 'password' => Hash::make('*Ingline.Sys#9420%SECURITY#')
]); ]);
Client::factory()->create([]);
} }
} }

View File

@ -60,6 +60,7 @@ @layer components {
@apply absolute right-5; @apply absolute right-5;
@apply rounded-xl; @apply rounded-xl;
@apply max-w-7 max-h-7; @apply max-w-7 max-h-7;
@apply shadow-md shadow-blue-400;
} }
.profile-list-items { .profile-list-items {

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -3,6 +3,7 @@
@section('content') @section('content')
<livewire:admin.create-user /> <livewire:admin.create-user />
<livewire:admin.add-client /> <livewire:admin.add-client />
<livewire:admin.show-users />
<div class="container grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6"> <div class="container grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">

View File

@ -22,7 +22,7 @@
<a href="{{ route('dashboard') }}">Início</a> <a href="{{ route('dashboard') }}">Início</a>
<div class="nav-bar-logo"> <div class="nav-bar-logo">
<a href="{{ route('dashboard') }}"> <a href="{{ route('dashboard') }}">
<img src="{{ Vite::asset('resources/images/logo.png') }}" alt="Logo"> <img src="{{ Vite::asset('resources/images/newlogo.png') }}" alt="Logo">
</a> </a>
</div> </div>
@ -42,8 +42,25 @@
src="{{ Vite::asset('resources/images/avatar-nexus.svg') }}" alt="Avatar"> src="{{ Vite::asset('resources/images/avatar-nexus.svg') }}" alt="Avatar">
</a> </a>
<ul class="profile-list-items" x-show="open"> <ul class="profile-list-items" x-show="open" x-transition:enter.duration.300ms
<h2 class="font-weight-bold text-center">Nexus</h2> x-transition:leave.duration.300ms>
<h2 class="font-bold text-center" x-show="open" x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 scale-90" x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-90">Nexus
</h2>
<li class="profile-items">
<a href="" class="profile-link">
Início
</a>
</li>
<li class="profile-items">
<a @click="$dispatch('show-users')" class="profile-link">
Administração
</a>
</li>
<li class="profile-items"> <li class="profile-items">
<a @click="$dispatch('open-create-user')" class="profile-link"> <a @click="$dispatch('open-create-user')" class="profile-link">
@ -51,18 +68,6 @@
</a> </a>
</li> </li>
<li class="profile-items">
<a href="" class="profile-link">
Visualizar Clientes
</a>
</li>
<li class="profile-items">
<a href="" class="profile-link">
Administração
</a>
</li>
<li class="profile-items"> <li class="profile-items">
<a @click="$dispatch('open-add-client')" class="profile-link"> <a @click="$dispatch('open-add-client')" class="profile-link">
Adicionar clientes Adicionar clientes

View File

@ -2,7 +2,7 @@
<div x-data="{ showModal: false }" x-on:user-created.window="showModal = false" <div x-data="{ showModal: false }" x-on:user-created.window="showModal = false"
x-on:open-create-user.window="showModal = true"> x-on:open-create-user.window="showModal = true">
<div x-show="showModal" class="modal-overlay"> <div x-show="showModal" class="modal-overlay" x-transition:enter.duration.300ms x-transition:leave.duration.300ms>
<div x-on:click.outside="showModal = false" x-show="showModal" x-transition:enter="transition-enter" <div x-on:click.outside="showModal = false" x-show="showModal" x-transition:enter="transition-enter"
x-transition:enter-start="transition-enter-start" x-transition:enter-end="transition-enter-end" x-transition:enter-start="transition-enter-start" x-transition:enter-end="transition-enter-end"
x-transition:leave="transition-leave" x-transition:leave-start="transition-leave-start" x-transition:leave="transition-leave" x-transition:leave-start="transition-leave-start"
@ -46,7 +46,7 @@
<div x-data="{ <div x-data="{
open: false, open: false,
selected: @entangle('permission_level'), selected: @entangle('permissions'),
options: { '0': 'Usuário', '1': 'Admin' } options: { '0': 'Usuário', '1': 'Admin' }
}" x-on:click.outside="open = false" class="select-wrapper"> }" x-on:click.outside="open = false" class="select-wrapper">
@ -93,7 +93,7 @@ class="absolute inset-y-0 left-0 flex items-center pl-3 text-blue-600">
</div> </div>
</div> </div>
@error('permission_level') <span class="error-text">{{ $message }}</span> @enderror @error('permissions') <span class="error-text">{{ $message }}</span> @enderror
</div> </div>
<div class="form-footer"> <div class="form-footer">

View File

@ -0,0 +1,4 @@
<div x-data="{showUsers: false}" x-on:show-users.window="showUsers = true">
</div>

View File

@ -1,19 +0,0 @@
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Bem vindo a página de criação dos usuários, <span style="background-color:rgb(89, 255, 255); border-radius: 0.3em; padding: 0.2em">{{Auth::user()->name}}!</span></h1>
<form action="{{ route('users.create') }}" method="POST" class="form-class">
@csrf
<input type="text" name="name" placeholder="Nome do usuário" class="form-input-class">
<input type="email" name="email" placeholder="Email do usuário" class="form-input-class">
<input type="password" name="password" placeholder="8 a 20 caracteres" class="form-input-class">
<button type="submit" class="form-button-class">Criar usuário</button>
</form>
</div>
@endsection