diff --git a/app/Http/Controllers/AddClientController.php b/app/Http/Controllers/AddClientController.php deleted file mode 100644 index 03eb091..0000000 --- a/app/Http/Controllers/AddClientController.php +++ /dev/null @@ -1,23 +0,0 @@ -clientService = $clientService; - } - - - public function addClient(Request $request) - { - - dd($this->clientService); - } -} diff --git a/app/Http/Controllers/LogoutController.php b/app/Http/Controllers/LogoutController.php index 903f193..ee8bbd0 100644 --- a/app/Http/Controllers/LogoutController.php +++ b/app/Http/Controllers/LogoutController.php @@ -15,6 +15,6 @@ public function logout(Request $request) $request->session()->invalidate(); $request->session()->regenerateToken(); - return redirect('/')->with('success', 'Logout efetuado com sucesso!'); + return redirect('/login')->with('success', 'Logout efetuado com sucesso!'); } } diff --git a/app/Livewire/Admin/AddClient.php b/app/Livewire/Admin/AddClient.php new file mode 100644 index 0000000..7b5e395 --- /dev/null +++ b/app/Livewire/Admin/AddClient.php @@ -0,0 +1,57 @@ +form->validate(); + + try { + $data = $this->form->all(); + $data['name'] = $data['client_name']; + // 4. Lida com o upload do arquivo de imagem + if ($this->form->profile_image_path) { + $path = $this->form->profile_image_path->store('client_logos', 'public'); + $data['profile_image_path'] = $path; + } + + // 5. Cria o cliente no banco de dados + Client::create($data); + // 6. Despacha um evento para atualizar outros componentes (ex: o grid de clientes) + $this->dispatch('client-added'); + // (Opcional) Envia uma notificação de sucesso + $this->dispatch('notify', message: 'Cliente adicionado com sucesso!'); + } catch (\Exception $e) { + dd($e); + $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() + { + return view('livewire.admin.add-client'); + } +} diff --git a/app/Livewire/Admin/CreateUser.php b/app/Livewire/Admin/CreateUser.php index 1418c83..15d39f3 100644 --- a/app/Livewire/Admin/CreateUser.php +++ b/app/Livewire/Admin/CreateUser.php @@ -19,7 +19,7 @@ class CreateUser extends Component // Nota: Adicionei 'same:password' para garantir que as senhas batem. protected $rules = [ 'name' => 'required|string|max:255', - 'email' => 'required|email', + 'email' => 'required|email|unique:users,email', 'password' => 'required|string|min:8', 'password_confirm' => 'required|string|same:password', // <-- Regra importante! 'permission_level' => 'required|boolean' // ou 'required|in:0,1' @@ -28,6 +28,7 @@ class CreateUser extends Component 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.', 'permission_level' => 'Defina o nível de autorização do usuário.' @@ -59,7 +60,8 @@ public function createUser(UserService $userService) $this->dispatch('user-created'); // Envia a mesma mensagem de sucesso do seu controller - session()->flash('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: @@ -70,9 +72,6 @@ public function createUser(UserService $userService) // 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. - if ($e->getMessage() == 'O e-mail já está cadastrado.') { - $this->addError('email', $e->getMessage()); - } $this->addError('general', $e->getMessage()); } diff --git a/app/Livewire/Forms/ClientForm.php b/app/Livewire/Forms/ClientForm.php new file mode 100644 index 0000000..2a8c0d0 --- /dev/null +++ b/app/Livewire/Forms/ClientForm.php @@ -0,0 +1,86 @@ +toArray(); + $data['has_call_center'] = (bool) $client->has_call_center; + $data['has_voice_gateway'] = (bool) $client->has_voice_gateway; + $data['has_fop2'] = (bool) $client->has_fop2; + + $this->fill($data); + } + + // 4. ADICIONADO: Método de Regras + /** + * Define as regras de validação para o formulário. + */ + public function rules() + { + return [ + 'client_name' => 'required|string|max:255', + 'legal_name' => 'required|string|max:255', + 'cnpj' => 'required|string|max:20|unique:clients,cnpj', + 'profile_image_path' => 'nullable|file|mimes:jpeg,png,bmp,gif,svg,webp|max:2048', // 2MB Max 'pbx_hosting' => 'nullable|string|max:255', + 'activation_date' => 'nullable|date', + 'carrier' => 'nullable|string|max:255', + 'access_type' => 'nullable|string|max:255', + 'server_ip' => 'nullable|ip', + 'root_password' => 'nullable|string', + 'has_call_center' => 'boolean', + 'has_voice_gateway' => 'boolean', + 'has_fop2' => 'boolean', + 'modules' => 'nullable|json', + 'whatsapp_number' => 'nullable|string|max:20', + 'whatsapp_activation_date' => 'nullable|date', + ]; + } + + // 5. ADICIONADO: Método de Mensagens Customizadas + /** + * Define as mensagens de erro customizadas. + */ + public function messages() + { + return [ + 'client_name.required' => 'O campo Nome Fantasia é obrigatório.', + 'client_name.max' => 'O Nome Fantasia não pode ter mais que 255 caracteres.', + + '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.max' => 'A imagem não pode ser maior que 2MB.', + + 'server_ip.ip' => 'Por favor, insira um endereço de IP válido.', + 'modules.json' => 'O campo módulos deve conter um formato JSON válido.', + + '*.date' => 'Por favor, insira uma data válida.', + '*.boolean' => 'Este campo deve ser verdadeiro ou falso.', + ]; + } +} diff --git a/app/Services/ClientService.php b/app/Services/ClientService.php index 0437a5e..4ed0af6 100644 --- a/app/Services/ClientService.php +++ b/app/Services/ClientService.php @@ -10,5 +10,8 @@ class ClientService { public function __construct(protected Client $client) {} - public function addClient() {} + public function addClient(array $client) + { + return Client::create($client); + } } diff --git a/app/Services/UserService.php b/app/Services/UserService.php index bed4b22..d72284f 100644 --- a/app/Services/UserService.php +++ b/app/Services/UserService.php @@ -11,10 +11,6 @@ class UserService public function __construct(protected User $user) {} public function createUser(array $user) { - if (User::where('email', '=', $user['email'])) { - throw new \Exception('O e-mail já está cadastrado.'); - } - return User::create($user); } } diff --git a/app/View/Components/FlashMessages.php b/app/View/Components/FlashMessages.php new file mode 100644 index 0000000..6b5d455 --- /dev/null +++ b/app/View/Components/FlashMessages.php @@ -0,0 +1,26 @@ +a { + color: black !important; + } + + .navbar-items>a { + color: black !important; + } +} @layer components { + /* Estilos globais */ + h1 { + @apply text-black font-semibold; + @apply border-b border-blue-500 rounded-md shadow-md shadow-blue-400; + @apply p-4 transition-all duration-300 transform hover:scale-105; + } + + * {} + + /* Fim estilos globais */ + /* body */ body { @apply bg-white h-screen w-screen; @@ -23,129 +49,6 @@ @layer components { /*End body */ - /* Header - Navbar */ - .nav-bar { - @apply flex flex-nowrap justify-center items-center mx-auto px-4 sm:px-6 lg:px-8 h-10; - @apply relative; - @apply bg-transparent text-black; - @apply fixed z-50 w-full; - - /* 1. ADICIONADO: A borda agora mora aqui */ - @apply border-b; - - /* 2. ESTADO BASE (Topo): A borda começa transparente */ - @apply border-transparent; - - /* 3. ADICIONADO: Também transiciona a cor da borda */ - @apply transition-colors duration-700 ease-in-out; - } - - .nav-bar::before { - content: ''; - @apply absolute top-0 left-0 w-full h-full; - - /* 2. ESTADO BASE (Topo): Fundo e Sombra */ - @apply bg-white; - @apply shadow-md shadow-blue-400; - /* 4. REMOVIDO: As classes 'border-b border-white' saíram daqui */ - - /* 3. TRANSIÇÃO (Correto) */ - @apply transition-all duration-700 ease-in-out; - - @apply -z-10; - } - - - .navbar-scrolled { - @apply border-white shadow-md; - } - - .navbar-scrolled::before { - @apply opacity-0; - @apply shadow-none; - } - - .nav-bar>.navbar-items>a:hover, - .nav-bar>.navbar-items>a { - @apply transition-all duration-300 transform hover:scale-105; - @apply mr-7; - @apply hover:border hover:shadow-md shadow-blue-400 border-blue-300 rounded-md p-1 transition-all duration-250 transform hover:scale-105; - } - - .nav-bar-logo { - /* Garante que a largura não ultrapasse 100% */ - @apply rounded-md max-w-25 mr-10; - height: auto; - /* Altura proporcional à largura */ - } - - .navbar-items { - @apply flex flex-nowrap justify-center items-center px-4 sm:px-6 lg:px-8 h-10; - } - - .profile-menu { - @apply absolute right-5; - @apply rounded-xl; - @apply max-w-7 max-h-7; - } - - .profile-list-items { - /* 1. Posicionamento (Correto) */ - @apply absolute top-full right-0 ml-4 mt-2; - - @apply block w-full; - /* Adicionei mt-2 para descolar do ícone */ - - /* 2. Largura Fixa (Mais limpo) */ - @apply w-56; - - /* 3. Estilos do Contêiner (Profissional) */ - @apply bg-white p-2 rounded-md shadow-xl; - /* Sombra mais forte */ - @apply border border-gray-200; - - /* 4. Divisórias Sutis entre os
-
-
-
-
-
-
-
-
-
-