Compare commits

..

No commits in common. "8dc2c82cc1f265012959f1ba7b7304a786852f57" and "63cf4dfa4b57d0289e55999e8d1882304ba54a3d" have entirely different histories.

7 changed files with 44 additions and 46 deletions

View File

@ -34,7 +34,7 @@ public function save(ClientService $clientService)
$client = $clientService->addClient($data); $client = $clientService->addClient($data);
$this->dispatch('client-added'); $this->dispatch('client-added');
$this->dispatch('notify', message: $client->name . ' adicionado com sucesso!'); $this->dispatch('notify', message: $client->name . ' Cliente adicionado com sucesso!');
} catch (\Exception $e) { } catch (\Exception $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');
} }

View File

@ -12,14 +12,14 @@ class CreateUser extends Component
public string $email = ''; public string $email = '';
public string $password = ''; public string $password = '';
public string $password_confirm = ''; public string $password_confirm = '';
public string $permissions = ''; public bool $permissions = false;
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', 'password_confirm' => 'required|string|same:password',
'permissions' => 'required|string|in:user,admin' 'permissions' => 'required|boolean'
]; ];
protected $messages = [ protected $messages = [
@ -28,7 +28,7 @@ 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.',
'permissions' => 'Escolha o nível de autorização do usuário.' 'permissions' => 'Defina o nível de autorização do usuário.',
]; ];
public function createUser(UserService $userService) public function createUser(UserService $userService)
@ -36,6 +36,12 @@ public function createUser(UserService $userService)
$validated = $this->validate($this->rules, $this->messages); $validated = $this->validate($this->rules, $this->messages);
if ($validated['permissions'] === true) {
$validated['permissions'] = array('admin');
} else {
$validated['permissions'] = array('user');
}
try { try {
$this->authorize('createUser', Auth::user()); $this->authorize('createUser', Auth::user());

View File

@ -4,7 +4,6 @@
use App\Livewire\Forms\ClientForm; use App\Livewire\Forms\ClientForm;
use App\Models\Client; use App\Models\Client;
use App\Services\ClientService;
use Livewire\Attributes\On; use Livewire\Attributes\On;
use Livewire\Component; use Livewire\Component;
use Exception; use Exception;
@ -14,11 +13,8 @@ class EditClient extends Component
public Client $client; public Client $client;
public ClientForm $clientForm; public ClientForm $clientForm;
// public ClientService $clientService;
#[On('update-client')] #[On('update-client')]
public function loadClient($id) public function loadClient($id)
{ {
try { try {
@ -31,19 +27,15 @@ public function loadClient($id)
$this->dispatch('notify', message: 'Ocorreu um erro inesperado ao editar o cliente. ' + $e); $this->dispatch('notify', message: 'Ocorreu um erro inesperado ao editar o cliente. ' + $e);
} }
} }
public function edit(ClientService $clientService) public function edit($clientId)
{ {
$data = $this->clientForm->validate(); $this->clientForm->validate();
try { try {
if (!$clientService->updateClient($this->client, $data)) { $this->clientForm->updateClient($this->client);
throw new Exception('O serviço não confirmou a atualização.'); $this->dispatch('notify', message: $this->client->client_name + ' atualizado com sucesso!');
}
$this->dispatch('client-updated');
$this->dispatch('notify', message: $this->clientForm->client_name . ' atualizado com sucesso!');
} catch (Exception $e) { } catch (Exception $e) {
$this->dispatch('notify', message: 'Falha na edição: ' . $e->getMessage(), type: 'error'); $this->dispatch('notify', message: 'Ocorreu um erro inesperado ao tentar confirmar edição do cliente. ' + $e);
} }
} }
public function render() public function render()

View File

@ -2,6 +2,7 @@
namespace App\Livewire\Forms; namespace App\Livewire\Forms;
use App\Services\ClientService;
use Exception; use Exception;
use Livewire\Attributes\Validate; use Livewire\Attributes\Validate;
use Livewire\Form; use Livewire\Form;
@ -25,6 +26,8 @@ class ClientForm extends Form
public $modules = ''; public $modules = '';
public $whatsapp_number = ''; public $whatsapp_number = '';
public $whatsapp_activation_date; public $whatsapp_activation_date;
public ClientService $clientService;
// Método para preencher o formulário (para edição futura) // Método para preencher o formulário (para edição futura)
public function addClient(Client $client) public function addClient(Client $client)
{ {
@ -37,6 +40,14 @@ public function addClient(Client $client)
$this->fill($data); $this->fill($data);
} }
public function updateClient(Client $client)
{
if(!$this->clientService->updateClient($client)){
throw new Exception('Ocorreu um erro.');
}
}
// 4. ADICIONADO: Método de Regras // 4. ADICIONADO: Método de Regras
/** /**
* Define as regras de validação para o formulário. * Define as regras de validação para o formulário.
@ -46,11 +57,7 @@ public function rules()
return [ return [
'client_name' => 'required|string|max:255', 'client_name' => 'required|string|max:255',
'legal_name' => 'required|string|max:255', 'legal_name' => 'required|string|max:255',
'cnpj' => [ 'cnpj' => 'required|string|max:20|unique:clients,cnpj',
'required',
'string',
'max:18',
],
'profile_image_path' => 'nullable|file|mimes:jpeg,png,bmp,gif,svg,webp|max:2048', 'profile_image_path' => 'nullable|file|mimes:jpeg,png,bmp,gif,svg,webp|max:2048',
'activation_date' => 'nullable|date', 'activation_date' => 'nullable|date',
'carrier' => 'nullable|string|max:255', 'carrier' => 'nullable|string|max:255',
@ -76,9 +83,6 @@ public function messages()
'client_name.required' => 'O campo Nome Fantasia é obrigatório.', 'client_name.required' => 'O campo Nome Fantasia é obrigatório.',
'client_name.max' => 'O Nome Fantasia não pode ter mais que 255 caracteres.', 'client_name.max' => 'O Nome Fantasia não pode ter mais que 255 caracteres.',
'cnpj.required' => 'O CNPJ é obrigatório.',
'cnpj.max' => 'O CNPJ deve ter no máximo 18 caracteres (incluindo pontuação).',
'cnpj.min' => 'O CNPJ está muito curto. Por favor, insira um CNPJ válido.',
'cnpj.unique' => 'Este CNPJ já está cadastrado em outro cliente.', 'cnpj.unique' => 'Este CNPJ já está cadastrado em outro cliente.',
'profile_image_path.image' => 'O arquivo deve ser uma imagem válida (jpg, png, etc.).', 'profile_image_path.image' => 'O arquivo deve ser uma imagem válida (jpg, png, etc.).',

View File

@ -20,9 +20,5 @@ public function addClient(array $client)
return Client::create($client); return Client::create($client);
} }
public function updateClient(Client $client, $data) public function updateClient($client) {}
{
$data['name'] = $data['client_name'];
return $client->update($data);
}
} }

View File

@ -47,7 +47,7 @@
<div x-data="{ <div x-data="{
open: false, open: false,
selected: @entangle('permissions'), selected: @entangle('permissions'),
options: { 'user': 'Usuário', 'admin': '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">
<button type="button" x-on:click="open = true" class="select-button"> <button type="button" x-on:click="open = true" class="select-button">
@ -63,10 +63,10 @@
</button> </button>
<div x-show="open" x-transition style="display: none;" class="select-options"> <div x-show="open" x-transition style="display: none;" class="select-options">
<div x-on:click="selected = 'user'; open = false" class="select-option" <div x-on:click="selected = '0'; open = false" class="select-option"
:class="{ 'selected-option': selected == 'user' }"> :class="{ 'selected-option': selected == '0' }">
<span class="option-label" :class="{ 'font-semibold': selected == 'user' }">Usuário</span> <span class="option-label" :class="{ 'font-semibold': selected == '0' }">Usuário</span>
<span x-show="selected == 'user'" <span x-show="selected == '0'"
class="absolute inset-y-0 left-0 flex items-center pl-3 text-blue-600"> 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" <svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor"> fill="currentColor">
@ -77,10 +77,10 @@ class="absolute inset-y-0 left-0 flex items-center pl-3 text-blue-600">
</span> </span>
</div> </div>
<div x-on:click="selected = 'admin'; open = false" class="select-option" <div x-on:click="selected = '1'; open = false" class="select-option"
:class="{ 'selected-option': selected == 'admin' }"> :class="{ 'selected-option': selected == '1' }">
<span class="option-label" :class="{ 'font-semibold': selected == 'admin' }">Admin</span> <span class="option-label" :class="{ 'font-semibold': selected == '1' }">Admin</span>
<span x-show="selected == 'admin'" <span x-show="selected == '1'"
class="absolute inset-y-0 left-0 flex items-center pl-3 text-blue-600"> 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" <svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor"> fill="currentColor">

View File

@ -14,7 +14,7 @@ class="fixed inset-0 bg-white/50 transition-opacity"></div>
class="fixed inset-y-0 right-0 flex max-w-full pl-10" @click.away="showEditClientModal = false"> class="fixed inset-y-0 right-0 flex max-w-full pl-10" @click.away="showEditClientModal = false">
<div class="w-screen max-w-3xl"> <div class="w-screen max-w-3xl">
<form wire:submit.prevent="edit" class="flex h-full flex-col overflow-y-scroll bg-white shadow-xl"> <form wire:submit="edit(clientId)" class="flex h-full flex-col overflow-y-scroll bg-white shadow-xl">
<div class="bg-white px-4 py-6 sm:px-6"> <div class="bg-white px-4 py-6 sm:px-6">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
@ -45,7 +45,7 @@ class="rounded-md text-blue-200 hover:text-white cursor-pointer focus:outline-no
<label for="client_name" class="form-label">Nome Fantasia *</label> <label for="client_name" class="form-label">Nome Fantasia *</label>
<input type="text" wire:model="clientForm.client_name" id="client_name" <input type="text" wire:model="clientForm.client_name" id="client_name"
class="form-input"> class="form-input">
@error('clientForm.client_name') <span @error('form.client_name') <span
class="text-red-500 text-sm">{{ $message }}</span> class="text-red-500 text-sm">{{ $message }}</span>
@enderror @enderror
</div> </div>
@ -53,14 +53,14 @@ class="text-red-500 text-sm">{{ $message }}</span>
<label for="legal_name" class="form-label">Razão Social *</label> <label for="legal_name" class="form-label">Razão Social *</label>
<input type="text" wire:model="clientForm.legal_name" id="legal_name" <input type="text" wire:model="clientForm.legal_name" id="legal_name"
class="form-input"> class="form-input">
@error('clientForm.legal_name') <span @error('form.legal_name') <span
class="text-red-500 text-sm">{{ $message }}</span> @enderror class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div> </div>
</div> </div>
<div class="mt-4"> <div class="mt-4">
<label for="cnpj" class="form-label">CNPJ *</label> <label for="cnpj" class="form-label">CNPJ *</label>
<input type="text" wire:model="clientForm.cnpj" id="cnpj" class="form-input"> <input type="text" wire:model="clientForm.cnpj" id="cnpj" class="form-input">
@error('clientForm.cnpj') <span class="text-red-500 text-sm">{{ $message }}</span> @error('form.cnpj') <span class="text-red-500 text-sm">{{ $message }}</span>
@enderror @enderror
</div> </div>
<div class="mt-4"> <div class="mt-4">
@ -72,7 +72,7 @@ class="form-file-input">
class="text-sm text-blue-600 mt-1"> class="text-sm text-blue-600 mt-1">
Enviando... Enviando...
</div> </div>
@error('clientForm.profile_image_path') <span @error('form.profile_image_path') <span
class="text-red-500 text-sm">{{ $message }}</span> @enderror class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div> </div>
</div> </div>
@ -105,7 +105,7 @@ class.="form-input" placeholder="Ex: SSH, AnyDesk, VPN">
<label for="server_ip" class="form-label">IP do Servidor</label> <label for="server_ip" class="form-label">IP do Servidor</label>
<input type="text" wire:model="clientForm.server_ip" id="server_ip" <input type="text" wire:model="clientForm.server_ip" id="server_ip"
class="form-input"> class="form-input">
@error('clientForm.server_ip') <span @error('form.server_ip') <span
class="text-red-500 text-sm">{{ $message }}</span> @enderror class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div> </div>
<div> <div>
@ -159,7 +159,7 @@ class="form-checkbox">
<label for="modules" class="form-label">Módulos Adicionais (JSON)</label> <label for="modules" class="form-label">Módulos Adicionais (JSON)</label>
<textarea wire:model="clientForm.modules" id="modules" rows="3" class="form-input" <textarea wire:model="clientForm.modules" id="modules" rows="3" class="form-input"
placeholder="Ex: {&quot;bi&quot;: true}"></textarea> placeholder="Ex: {&quot;bi&quot;: true}"></textarea>
@error('clientForm.modules') <span class="text-red-500 text-sm">{{ $message }}</span> @error('form.modules') <span class="text-red-500 text-sm">{{ $message }}</span>
@enderror @enderror
</div> </div>
</div> </div>