Compare commits
5 Commits
e62e92f7bb
...
4d6d21da6f
| Author | SHA1 | Date |
|---|---|---|
|
|
4d6d21da6f | |
|
|
ac3ed58dae | |
|
|
9024fc4439 | |
|
|
5bbbd78557 | |
|
|
abd87a7894 |
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use App\Models\User;
|
||||
use App\Services\UserService;
|
||||
|
||||
|
||||
class CreateUserController extends Controller
|
||||
{
|
||||
public function __construct(protected UserService $userService) {}
|
||||
public function createUsers(Request $request): RedirectResponse
|
||||
{
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|email|unique:users',
|
||||
'password' => 'required|string|min:8',
|
||||
'password_confirm' => 'required|string|min:8'
|
||||
]);
|
||||
|
||||
try {
|
||||
$user = $this->userService->createUser($validated);
|
||||
return redirect()->route('users.view', ['user' => $user], 200)->with('message', 'Usuário cadastrado com sucesso!');
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('users.create', status: 403)->with('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@ class CreateUser extends Component
|
|||
* Note como injetamos o UserService direto no método!
|
||||
* O Livewire cuida disso para você, assim como o Laravel faz nos controllers.
|
||||
*/
|
||||
public function save(UserService $userService)
|
||||
public function createUser(UserService $userService)
|
||||
{
|
||||
|
||||
// 3. Valida as propriedades públicas ($this->name, $this->email, etc.)
|
||||
|
|
|
|||
|
|
@ -25,29 +25,81 @@ @layer components {
|
|||
|
||||
/* Header - Navbar */
|
||||
.nav-bar {
|
||||
@apply flex flex-nowrap justify-center items-center mx-auto px-4 sm:px-6 lg:px-8 h-10 w-screen;
|
||||
@apply flex flex-nowrap justify-center items-center mx-auto px-4 sm:px-6 lg:px-8 h-10;
|
||||
@apply relative;
|
||||
/* Colors */
|
||||
@apply bg-white text-black;
|
||||
/* Border */
|
||||
@apply border-b border-white shadow-md shadow-blue-400;
|
||||
}
|
||||
|
||||
.nav-bar a:hover,
|
||||
.nav-bar a {
|
||||
.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 {
|
||||
@apply absolute left-0;
|
||||
/* Garantir que o container da logo seja posicionado corretamente */
|
||||
max-width: 8%;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
.profile-list-items {
|
||||
/* 1. Posicionamento (Correto) */
|
||||
@apply absolute top-full right-0 ml-4;
|
||||
|
||||
@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 <li> */
|
||||
@apply divide-y divide-gray-100;
|
||||
}
|
||||
|
||||
.profile-link {
|
||||
/* Você pode aplicar isso direto no <a> */
|
||||
/* 1. FAZ O LINK PREENCHER O <li> */
|
||||
@apply block w-full;
|
||||
|
||||
}
|
||||
|
||||
.profile-items {
|
||||
/* 1. Limpeza (Classes antigas removidas) */
|
||||
|
||||
/* 2. Espaçamento Interno (Respiro) */
|
||||
@apply px-4 py-2;
|
||||
|
||||
/* 3. Estilos de Texto */
|
||||
@apply text-sm text-gray-700;
|
||||
|
||||
/* 4. Interatividade */
|
||||
@apply hover:bg-blue-100 cursor-pointer;
|
||||
|
||||
/* 5. Transição Suave */
|
||||
@apply transition-colors duration-150 ease-in-out;
|
||||
|
||||
/* 6. Cantos do Hover */
|
||||
@apply rounded-md;
|
||||
}
|
||||
|
||||
.nav-bar-logo img {
|
||||
@apply w-full;
|
||||
/* Largura 100% para se ajustar ao container */
|
||||
|
|
@ -55,8 +107,7 @@ @layer components {
|
|||
/* Mantém a proporção original da imagem */
|
||||
}
|
||||
|
||||
.nav-bar>form>button {
|
||||
@apply mr-7;
|
||||
.nav-bar>.navbar-items>form>button {
|
||||
@apply hover:border hover:shadow-md hover:scale-105 hover:cursor-pointer shadow-blue-400 border-blue-300 rounded-md p-1 transition-all duration-250 transform;
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 101 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 63 KiB |
|
|
@ -16,24 +16,56 @@
|
|||
</head>
|
||||
<header>
|
||||
<nav class="nav-bar">
|
||||
@auth
|
||||
<div class="navbar-items">
|
||||
<a href="{{ route('dashboard') }}">Início</a>
|
||||
<div class="nav-bar-logo">
|
||||
<!-- <img src="{{ Vite::asset('resources/images/logo.png') }}" alt="Logo"> -->
|
||||
<a href="{{ route('dashboard') }}">
|
||||
<img src="{{ Vite::asset('resources/images/logo.png') }}" alt="Logo">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@auth
|
||||
<a href="{{ route('dashboard') }}">Início</a>
|
||||
<form action="{{ route('logout') }}" method="post">
|
||||
@csrf
|
||||
<button type="submit">
|
||||
Logout
|
||||
Sair
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div x-data="{open: false}" x-on:click.outside="open = false" class="profile-menu max-w-12">
|
||||
<a x-on:click="open = !open" class="cursor-pointer">
|
||||
<img class="w-15 h-15 rounded-full object-cover"
|
||||
src="{{ Vite::asset('resources/images/avatar-nexus.svg') }}" alt="Avatar">
|
||||
</a>
|
||||
|
||||
<ul class="profile-list-items" x-show="open">
|
||||
|
||||
<li class="profile-items">
|
||||
<a href="" class="profile-link">
|
||||
Adicionar Clientes
|
||||
</a>
|
||||
</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>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
@endauth
|
||||
|
||||
@guest
|
||||
<div>Bem vindo ao Nexus.</div>
|
||||
@endguest
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<div x-data="{ showModal: false }" x-on:create-user.window="showModal = false">
|
||||
<button x-on:click="showModal = true" class="px-4 py-2 bg-blue-600 text-white rounded ...">
|
||||
<button x-on:click="showModal = true" class="cursor-pointer px-4 py-2 bg-blue-600 text-white rounded ...">
|
||||
Criar Novo Usuário
|
||||
</button>
|
||||
|
||||
|
|
@ -9,13 +9,16 @@
|
|||
</div>
|
||||
@endif
|
||||
|
||||
<div x-show="showModal" class="fixed inset-0 z-50 flex items-center justify-center bg-white/35"
|
||||
style="display: none;">
|
||||
<div x-on:click.outside="showModal = false" class="bg-white rounded-lg shadow-xl w-full max-w-lg p-6">
|
||||
<div x-show="showModal" class="fixed inset-0 z-50 flex items-center justify-center bg-white/35">
|
||||
<div x-on:click.outside="showModal = false" x-show="showModal"
|
||||
x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 scale-90"
|
||||
x-transition:enter-end="opacity-100 scale-100" x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-90"
|
||||
class="bg-white rounded-lg shadow-xl w-full max-w-lg p-6">
|
||||
|
||||
<h3 class="text-lg font-medium text-gray-900">Novo Usuário Nexus</h3>
|
||||
|
||||
<form wire:submit.prevent="save" class="mt-4 space-y-4">
|
||||
<form wire:submit.prevent="createUser" class="mt-4 space-y-4">
|
||||
|
||||
@error('general')
|
||||
<div class="p-3 bg-red-100 text-red-700 rounded">
|
||||
|
|
@ -25,21 +28,21 @@
|
|||
|
||||
<div>
|
||||
<label for="name" class="block text-sm ...">Nome</label>
|
||||
<input type="text" wire:model="name" id="name"
|
||||
<input type="text" wire:model.defer="name" id="name"
|
||||
class="mt-1 block w-full border-2 border-gray-200 rounded-md outline-none hover:border-blue-200 transition delay-150 duration-300 ease-in-out focus:border-blue-200">
|
||||
@error('name') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email" class="block text-sm ...">Email</label>
|
||||
<input type="email" wire:model="email" id="email"
|
||||
<input type="email" wire:model.defer="email" id="email"
|
||||
class="mt-1 block w-full border-2 border-gray-200 rounded-md outline-none hover:border-blue-200 transition delay-150 duration-300 ease-in-out focus:border-blue-200">
|
||||
@error('email') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password" class="block text-sm ...">Senha</label>
|
||||
<input type="password" wire:model="password" id="password"
|
||||
<input type="password" wire:model.defer="password" id="password"
|
||||
class="mt-1 block w-full border-2 border-gray-200 rounded-md outline-none hover:border-blue-200 transition delay-150 duration-300 ease-in-out focus:border-blue-200">
|
||||
@error('password') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
|
@ -54,53 +57,54 @@ class="mt-1 block w-full border-2 border-gray-200 rounded-md outline-none hover:
|
|||
<div>
|
||||
<label for="permissions" class="block text-sm font-medium text-gray-700">Permissões</label>
|
||||
|
||||
<div
|
||||
x-data="{
|
||||
<div x-data="{
|
||||
open: false,
|
||||
selected: @entangle('permission_level'),
|
||||
options: { '0': 'Usuário', '1': 'Admin' }
|
||||
}"
|
||||
x-on:click.outside="open = false" class="relative mt-1"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
x-on:click="open = true" class="relative h-10 w-40 cursor-default rounded-lg border border-gray-300 bg-white py-2 pl-3 pr-10 text-left shadow-sm p-2"
|
||||
>
|
||||
}" x-on:click.outside="open = false" class="relative mt-1">
|
||||
<button type="button" x-on:click="open = true"
|
||||
class="relative h-10 w-40 cursor-default rounded-lg border border-gray-300 bg-white py-2 pl-3 pr-10 text-left shadow-sm p-2">
|
||||
<span class="block truncate" x-text="options[selected]"></span>
|
||||
|
||||
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<svg class="h-5 w-5 text-gray-400" 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 class="h-5 w-5 text-gray-400" 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="absolute z-10 mt-1 w-full max-h-60 overflow-auto rounded-md bg-white py-1 shadow-lg"
|
||||
>
|
||||
<div
|
||||
x-on:click="selected = '0'; open = false" class="relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900 hover:bg-blue-100"
|
||||
<div x-show="open" x-transition style="display: none;"
|
||||
class="absolute z-10 mt-1 w-full max-h-60 overflow-auto rounded-md bg-white py-1 shadow-lg">
|
||||
<div x-on:click="selected = '0'; open = false"
|
||||
class="relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900 hover:bg-blue-100"
|
||||
:class="{ 'bg-blue-50': selected == '0' }">
|
||||
<span class="block truncate" :class="{ 'font-semibold': selected == '0' }">Usuário</span>
|
||||
<span x-show="selected == '0'" 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" />
|
||||
<span class="block truncate"
|
||||
:class="{ 'font-semibold': selected == '0' }">Usuário</span>
|
||||
<span x-show="selected == '0'"
|
||||
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 = '1'; open = false"
|
||||
<div x-on:click="selected = '1'; open = false"
|
||||
class="relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900 hover:bg-blue-100"
|
||||
:class="{ 'bg-blue-50': selected == '1' }"
|
||||
>
|
||||
:class="{ 'bg-blue-50': selected == '1' }">
|
||||
<span class="block truncate" :class="{ 'font-semibold': selected == '1' }">Admin</span>
|
||||
<span x-show="selected == '1'" 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" />
|
||||
<span x-show="selected == '1'"
|
||||
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>
|
||||
|
|
@ -112,12 +116,13 @@ class="relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900 hover:b
|
|||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-3 pt-4">
|
||||
<button type="button" @click="showModal = false" class="px-4 py-2 rounded-md bg-gray-200 ...">
|
||||
<button type="button" @click="showModal = false"
|
||||
class="cursor-pointer px-4 py-2 rounded-md bg-gray-200 ...">
|
||||
Cancelar
|
||||
</button>
|
||||
<button type="submit" class="px-4 py-2 bg-blue-600 rounded-md text-white ...">
|
||||
<span wire:loading.remove wire:target="save">Salvar</span>
|
||||
<span wire:loading wire:target="save">Salvando...</span>
|
||||
<button type="submit" class="cursor-pointer px-4 py-2 bg-blue-600 rounded-md text-white ...">
|
||||
<span wire:loading.remove wire:target="createUser">Salvar</span>
|
||||
<span wire:loading wire:target="createUser" class="cursor-progress">Salvando...</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
Loading…
Reference in New Issue