feat: Concluindo funcionalidade para edição de usuários.
This commit is contained in:
parent
d89f8cf52e
commit
76226ab7f7
|
|
@ -5,21 +5,28 @@
|
|||
use Livewire\Component;
|
||||
use Livewire\Attributes\On;
|
||||
use App\Models\User;
|
||||
use App\Services\UserService;
|
||||
use Exception;
|
||||
|
||||
class DeleteUser extends Component
|
||||
{
|
||||
#[On('confirm-delete')]
|
||||
public function deleteUser($payload)
|
||||
|
||||
#[On('confirm-delete-user')]
|
||||
public function deleteUser(UserService $userService, $payload)
|
||||
{
|
||||
|
||||
$deletedClient = User::findOrFail($payload);
|
||||
$deletedUser = User::findOrFail($payload);
|
||||
try {
|
||||
if ($deletedUser) {
|
||||
$deletedUser = $userService->deleteUser($deletedUser);
|
||||
}
|
||||
|
||||
if ($deletedClient) {
|
||||
$deletedClient->delete();
|
||||
$this->dispatch('user-deleted');
|
||||
$this->dispatch('notify', message: $deletedUser->name . ' Usuário excluído com sucesso!');
|
||||
} catch (Exception $e) {
|
||||
$this->dispatch('user-delete-error');
|
||||
$this->dispatch('notify', message: $e->getMessage());
|
||||
}
|
||||
|
||||
$this->dispatch('user-deleted');
|
||||
$this->dispatch('notify', message: 'Cliente excluído com sucesso!');
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
|
|
|||
|
|
@ -1,13 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire\Admin\User\EditUser;
|
||||
namespace App\Livewire\Admin\User;
|
||||
|
||||
use App\Livewire\Forms\UserForm;
|
||||
use App\Models\User;
|
||||
use Livewire\Component;
|
||||
use Livewire\Attributes\On;
|
||||
use App\Services\UserService;
|
||||
|
||||
class EditUser extends Component
|
||||
{
|
||||
|
||||
|
||||
public UserService $userService;
|
||||
public User $user;
|
||||
public UserForm $userForm;
|
||||
#[On('update-user')]
|
||||
public function loadUser($id)
|
||||
{
|
||||
try {
|
||||
$this->user = User::find($id);
|
||||
|
||||
|
||||
if ($this->user) {
|
||||
$this->userForm->editUser($this->user);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('notify', message: 'Ocorreu um erro inesperado ao editar o usuário. ' . $e);
|
||||
}
|
||||
}
|
||||
public function editUser(UserService $userService)
|
||||
{
|
||||
$data = $this->userForm->validate();
|
||||
try {
|
||||
if (!$userService->updateUser($this->user, $data)) {
|
||||
throw new \Exception('O serviço não confirmou a atualização.');
|
||||
}
|
||||
|
||||
$this->dispatch('user-updated');
|
||||
$this->dispatch('notify', message: $this->clientForm->client_name . ' atualizado com sucesso!');
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('notify', message: 'Falha na edição: ' . $e->getMessage(), type: 'error');
|
||||
}
|
||||
}
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.admin.users.edit-user.php');
|
||||
return view('livewire.admin.users.edit-user');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire\Forms;
|
||||
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Form;
|
||||
use App\Models\User;
|
||||
|
||||
class UserForm extends Form
|
||||
{
|
||||
|
||||
|
||||
public string $name = '';
|
||||
public string $email = '';
|
||||
public string $password = '';
|
||||
public string $password_confirm = '';
|
||||
public string $permissions = '';
|
||||
|
||||
|
||||
public function editUser(User $user)
|
||||
{
|
||||
$data = $user->toArray();
|
||||
|
||||
$data['permissions'] = $data['permissions'][0];
|
||||
|
||||
$this->fill($data);
|
||||
}
|
||||
|
||||
protected $rules = [
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'email|unique:users,email',
|
||||
'password' => 'string|min:8',
|
||||
'password_confirm' => 'string|same:password',
|
||||
'permissions' => 'required|string|in:user,admin'
|
||||
];
|
||||
|
||||
protected $messages = [
|
||||
'name' => 'Nome precisa ser informado.',
|
||||
'email' => 'O email precisa ser informado.',
|
||||
'email.unique' => 'O email informado já foi cadastrado anteriormente.',
|
||||
'password' => 'A senha precisa ter 8 ou mais caracteres.',
|
||||
'password_confirm' => 'As senhas não coincidem.',
|
||||
'permissions' => 'Escolha o nível de autorização do usuário.'
|
||||
];
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
namespace App\Services;
|
||||
|
||||
use App\Models\User;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class UserService
|
||||
|
|
@ -19,4 +21,19 @@ public function showUsers()
|
|||
$users = User::all();
|
||||
return $users;
|
||||
}
|
||||
|
||||
public function updateUser(User $user, $data)
|
||||
{
|
||||
return $user->update($data);
|
||||
}
|
||||
|
||||
public function deleteUser($user)
|
||||
{
|
||||
if ($user->id === Auth::user()->id) {
|
||||
throw new Exception('Não é possível excluir seu próprio usuário.', 403);
|
||||
}
|
||||
|
||||
$user->delete();
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
- 'showQuestion' controla a visibilidade.
|
||||
- '@sure.window' é o evento que dispara a abertura.
|
||||
-->
|
||||
<div x-data="{showQuestion: false, clientId: null}" @sure.window="showQuestion = true; clientId = $event.detail.id"
|
||||
x-cloak {{-- x-cloak é bom para evitar "piscadas" na tela --}}>
|
||||
<div x-data="{showQuestion: false, clientId: null, user: false}"
|
||||
@sure.window="showQuestion = true; clientId = $event.detail.id; user = $event.detail.isUser;" x-cloak {{-- x-cloak é
|
||||
bom para evitar "piscadas" na tela --}}>
|
||||
|
||||
<!--
|
||||
1. O OVERLAY (Fundo)
|
||||
|
|
@ -58,12 +59,14 @@ class="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-
|
|||
O botão "Sim, Excluir" deve vir primeiro no HTML
|
||||
para o 'flex-row-reverse' funcionar.
|
||||
-->
|
||||
<button type="button" @click="$dispatch('confirm-delete', [clientId]); showQuestion = false"
|
||||
<button type="button"
|
||||
@click="if(user){$dispatch('confirm-delete-user', [clientId]);}else{$dispatch('confirm-delete', [clientId]); } showQuestion = false"
|
||||
class="btn-submit bg-red-600 hover:bg-red-700 focus:ring-red-500 w-full sm:w-auto cursor-pointer">
|
||||
Sim, Excluir
|
||||
</button>
|
||||
|
||||
<button type="button" @click="showQuestion = false" class="btn-cancel mt-3 sm:mt-0 w-full sm:w-auto cursor-pointer">
|
||||
<button type="button" @click="showQuestion = false"
|
||||
class="btn-cancel mt-3 sm:mt-0 w-full sm:w-auto cursor-pointer">
|
||||
Cancelar
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@
|
|||
@section('content')
|
||||
<livewire:admin.user.create-user />
|
||||
<livewire:admin.client.add-client />
|
||||
<livewire:admin.user.delete-user>
|
||||
<livewire:admin.show-users />
|
||||
<livewire:admin.client.delete-client />
|
||||
<x-are-you-sure />
|
||||
<livewire:show-client />
|
||||
<livewire:admin.client.edit-client />
|
||||
<livewire:admin.user.edit-user />
|
||||
@endsection
|
||||
|
|
@ -1,17 +1,12 @@
|
|||
<div x-data="{ showUsers: @entangle('showUsers') }" x-cloak
|
||||
x-on:show-users.window="showUsers = true"
|
||||
x-on:close-users-modal.window="showUsers = false"
|
||||
class="relative z-50"
|
||||
>
|
||||
<div x-data="{ showUsers: false}" x-cloak x-on:show-users.window="showUsers = true"
|
||||
x-on:close-users-modal.window="showUsers = false" class="relative z-50">
|
||||
<div x-show="showUsers" class="modal-overlay" x-transition:enter.duration.300ms x-transition:leave.duration.300ms>
|
||||
<div x-on:click.outside="showUsers = false" x-show="showUsers"
|
||||
x-transition:enter="transition-enter" 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-end="transition-leave-end"
|
||||
class="modal-container w-full max-w-2xl"
|
||||
>
|
||||
<div x-on:click.outside="showUsers = false" x-show="showUsers" x-transition:enter="transition-enter"
|
||||
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-end="transition-leave-end" class="modal-container w-full max-w-2xl">
|
||||
<h3 class="modal-title">Usuários Cadastrados no Nexus</h3>
|
||||
|
||||
|
||||
<div class="user-list-content">
|
||||
<div class="user-grid">
|
||||
@forelse ($users as $user)
|
||||
|
|
@ -23,22 +18,28 @@ class="modal-container w-full max-w-2xl"
|
|||
<div class="user-details">
|
||||
{{-- <span class="user-permission">{{ ucfirst($user->permissions) }}</span> --}}
|
||||
<span class="user-status">Ativo</span>
|
||||
|
||||
|
||||
<div class="user-actions-group">
|
||||
|
||||
<button @click="$dispatch('open-edit-user', { id: '{{ $user->id }}' }); showUsers = false"
|
||||
class="action-button text-blue-600 hover:text-blue-800 cursor-pointer"
|
||||
title="Editar Usuário">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
|
||||
|
||||
<button
|
||||
@click="$dispatch('update-user', { id: '{{ $user->id }}' }); showUsers = false"
|
||||
class="action-button text-blue-600 hover:text-blue-800 cursor-pointer"
|
||||
title="Editar Usuário">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none"
|
||||
viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button @click="$dispatch('sure', { id: '{{ $user->id }}' }); showUsers = false"
|
||||
class="action-button text-red-600 hover:text-red-800 cursor-pointer"
|
||||
title="Excluir Usuário">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.86 11.2a2 2 0 01-2 1.8H7.86a2 2 0 01-2-1.8L4.01 7h14.98zM9 5h6" />
|
||||
|
||||
<button
|
||||
@click="$dispatch('sure', { id: '{{ $user->id }}', isUser: true }); showUsers = false"
|
||||
class="action-button text-red-600 hover:text-red-800 cursor-pointer"
|
||||
title="Excluir Usuário">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none"
|
||||
viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M19 7l-.86 11.2a2 2 0 01-2 1.8H7.86a2 2 0 01-2-1.8L4.01 7h14.98zM9 5h6" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -49,9 +50,9 @@ class="action-button text-red-600 hover:text-red-800 cursor-pointer"
|
|||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-footer">
|
||||
<button type="button" @click="showUsers = false" class="btn-cancel">
|
||||
<button type="button" @click="showUsers = false" class="btn-cancel cursor-pointer">
|
||||
Fechar
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
<!-- create-user.blade.php -->
|
||||
<div x-data="{ showModalUpdate: false }" x-on:user-created.window="showModalUpdate = false"
|
||||
x-on:update-user.window="showModalUpdate = true">
|
||||
|
||||
<div x-show="showModalUpdate" class="modal-overlay" x-transition:enter.duration.300ms
|
||||
x-transition:leave.duration.300ms>
|
||||
<div x-on:click.outside="showModalUpdate = false" x-show="showModalUpdate" x-transition:enter="transition-enter"
|
||||
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-end="transition-leave-end" class="modal-container">
|
||||
|
||||
<h3 class="modal-title">Novo Usuário Nexus</h3>
|
||||
|
||||
<form wire:submit.prevent="editUser" class="form-wrapper">
|
||||
@error('general')
|
||||
<div class="error-box">
|
||||
<strong>Erro:</strong> {{ $message }}
|
||||
</div>
|
||||
@enderror
|
||||
|
||||
<div>
|
||||
<label for="name" class="form-label">Nome</label>
|
||||
<input type="text" wire:model.defer="userForm.name" id="name" class="form-input">
|
||||
@error('name') <span class="error-text">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" wire:model.defer="userForm.email" id="email" class="form-input">
|
||||
@error('email') <span class="error-text">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password" class="form-label">Senha</label>
|
||||
<input type="password" wire:model.defer="userForm.password" id="password" class="form-input">
|
||||
@error('password') <span class="error-text">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password_confirm" class="form-label">Confirmar Senha</label>
|
||||
<input type="password" wire:model="userForm.password_confirm" id="password_confirm"
|
||||
class="form-input">
|
||||
@error('password_confirm') <span class="error-text">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="permissions" class="form-label">Permissões</label>
|
||||
|
||||
<div x-data="{
|
||||
open: false,
|
||||
selected: @entangle('userForm.permissions'),
|
||||
options: { 'user': 'Usuário', 'admin': 'Admin' }
|
||||
}" x-on:click.outside="open = false" class="select-wrapper">
|
||||
|
||||
<button type="button" x-on:click="open = true" class="select-button">
|
||||
<span class="select-text" x-text="options[selected]"></span>
|
||||
<span class="select-icon">
|
||||
<svg class="select-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
|
||||
fill="currentColor">
|
||||
<path fill-rule="evenodd"
|
||||
d="M10 3a.75.75 0 01.53.22l3.5 3.5a.75.75 0 01-1.06 1.06L10 4.81 6.53 8.28a.75.75 0 01-1.06-1.06l3.5-3.5A.75.75 0 0110 3zm-3.5 9.28a.75.75 0 011.06 0L10 15.19l3.47-3.47a.75.75 0 111.06 1.06l-3.5 3.5a.75.75 0 01-1.06 0l-3.5-3.5a.75.75 0 010-1.06z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div x-show="open" x-transition style="display: none;" class="select-options">
|
||||
<div x-on:click="selected = 'user'; open = false" class="select-option"
|
||||
:class="{ 'selected-option': selected == 'user' }">
|
||||
<span class="option-label"
|
||||
:class="{ 'font-semibold': selected == 'user' }">Usuário</span>
|
||||
<span x-show="selected == 'user'"
|
||||
class="absolute inset-y-0 left-0 flex items-center pl-3 text-blue-600">
|
||||
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
|
||||
fill="currentColor">
|
||||
<path fill-rule="evenodd"
|
||||
d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div x-on:click="selected = 'admin'; open = false" class="select-option"
|
||||
:class="{ 'selected-option': selected == 'admin' }">
|
||||
<span class="option-label"
|
||||
:class="{ 'font-semibold': selected == 'admin' }">Admin</span>
|
||||
<span x-show="selected == 'admin'"
|
||||
class="absolute inset-y-0 left-0 flex items-center pl-3 text-blue-600">
|
||||
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
|
||||
fill="currentColor">
|
||||
<path fill-rule="evenodd"
|
||||
d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@error('permissions') <span class="error-text">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div class="form-footer">
|
||||
<button type="button" @click="showModalUpdate = false" class="btn-cancel">
|
||||
Cancelar
|
||||
</button>
|
||||
|
||||
<button type="submit" class="btn-submit">
|
||||
<span wire:loading.remove wire:target="editUser">Salvar</span>
|
||||
<span wire:loading wire:target="editUser" class="loading">Salvando...</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<div>
|
||||
{{-- A good traveler has no fixed plans and is not intent upon arriving. --}}
|
||||
</div>
|
||||
Loading…
Reference in New Issue