Files
construprogress/resources/views/livewire/user-form.blade.php
T

338 lines
20 KiB
PHP
Raw Normal View History

<div>
<x-slot name="header">
<div class="flex items-center gap-3">
<a href="{{ route('admin.users') }}" class="btn btn-ghost btn-sm px-2" wire:navigate>
<x-heroicon-o-arrow-left class="w-4 h-4" />
</a>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ $user ? 'Editar usuario: ' . $user->name : 'Nuevo usuario' }}
</h2>
</div>
</x-slot>
<div class="py-8">
<div class="max-w-3xl mx-auto sm:px-6 lg:px-8">
@if(session('notify'))
<div class="alert alert-success mb-4">
<x-heroicon-o-check-circle class="w-5 h-5" />
{{ session('notify') }}
</div>
@endif
<div class="card bg-base-100 shadow">
<div class="card-body p-8">
<form wire:submit.prevent="save">
@if($errors->any())
<div class="alert alert-error text-sm mb-6">
<x-heroicon-o-exclamation-circle class="w-5 h-5 shrink-0" />
<ul class="list-disc pl-3 space-y-0.5">
@foreach($errors->all() as $e) <li>{{ $e }}</li> @endforeach
</ul>
</div>
@endif
{{-- ══════════════════════════════════════════════════════════
1. INFORMACIÓN PERSONAL
══════════════════════════════════════════════════════════ --}}
<div class="pb-6 mb-6 border-b border-base-200">
<h3 class="text-xs font-semibold text-gray-400 uppercase tracking-widest mb-4">
Información personal
</h3>
<div class="space-y-4">
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Título de cortesía
</label>
<div class="flex-1">
<select wire:model="title" class="select select-bordered w-full max-w-xs">
<option value=""> Sin título </option>
<option value="Sr.">Sr.</option>
<option value="Sra.">Sra.</option>
<option value="Dr.">Dr.</option>
<option value="Dra.">Dra.</option>
<option value="Ing.">Ing.</option>
<option value="Arq.">Arq.</option>
<option value="Prof.">Prof.</option>
</select>
</div>
</div>
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Apellidos <span class="text-error">*</span>
</label>
<div class="flex-1">
<input type="text" wire:model="lastName"
class="input input-bordered w-full"
placeholder="García López" />
@error('lastName') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
</div>
</div>
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Nombre <span class="text-error">*</span>
</label>
<div class="flex-1">
<input type="text" wire:model="firstName"
class="input input-bordered w-full"
placeholder="Ana" />
@error('firstName') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
</div>
</div>
</div>
</div>
{{-- ══════════════════════════════════════════════════════════
2. VALIDACIÓN
══════════════════════════════════════════════════════════ --}}
<div class="pb-6 mb-6 border-b border-base-200">
<h3 class="text-xs font-semibold text-gray-400 uppercase tracking-widest mb-4">
Validación de acceso
</h3>
<div class="space-y-4">
{{-- Intervalo de fechas --}}
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Válido desde / hasta
<p class="text-xs text-gray-400 font-normal mt-0.5">Vacío = sin límite</p>
</label>
<div class="flex-1 flex items-center gap-2">
<input type="date" wire:model="validFrom"
class="input input-bordered flex-1" />
<span class="text-gray-400 shrink-0"></span>
<input type="date" wire:model="validUntil"
class="input input-bordered flex-1" />
</div>
</div>
@error('validFrom') <div class="flex gap-4"><div class="w-48 shrink-0"></div><p class="text-error text-xs flex-1">{{ $message }}</p></div> @enderror
@error('validUntil') <div class="flex gap-4"><div class="w-48 shrink-0"></div><p class="text-error text-xs flex-1">{{ $message }}</p></div> @enderror
{{-- Contraseña con generador --}}
<div class="flex items-start gap-4"
x-data="{
show: false,
generate() {
const upper = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
const lower = 'abcdefghjkmnpqrstuvwxyz';
const digits = '23456789';
const symbols = '!@#$%&*';
const all = upper + lower + digits + symbols;
let pwd = upper[Math.floor(Math.random()*upper.length)]
+ lower[Math.floor(Math.random()*lower.length)]
+ digits[Math.floor(Math.random()*digits.length)]
+ symbols[Math.floor(Math.random()*symbols.length)];
for (let i = 4; i < 12; i++) {
pwd += all[Math.floor(Math.random()*all.length)];
}
pwd = pwd.split('').sort(() => Math.random()-0.5).join('');
$wire.set('formPassword', pwd);
this.show = true;
}
}">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Contraseña
@if(!$user) <span class="text-error">*</span> @endif
@if($user)
<p class="text-xs text-gray-400 font-normal mt-0.5">Vacío = no cambiar</p>
@endif
</label>
<div class="flex-1 space-y-2">
<div class="flex gap-2">
<label class="input input-bordered flex items-center gap-2 flex-1">
<x-heroicon-o-lock-closed class="w-4 h-4 opacity-40 shrink-0" />
<input wire:model="formPassword" class="grow"
:type="show ? 'text' : 'password'"
placeholder="{{ $user ? '••••••••' : 'Mínimo 8 caracteres' }}" />
<button type="button" @click="show = !show"
class="opacity-50 hover:opacity-100 transition-opacity">
<template x-if="show">
<x-heroicon-o-eye-slash class="w-4 h-4" />
</template>
<template x-if="!show">
<x-heroicon-o-eye class="w-4 h-4" />
</template>
</button>
</label>
<button type="button" @click="generate()"
class="btn btn-outline btn-sm gap-1 shrink-0"
title="Generar contraseña aleatoria">
<x-heroicon-o-arrow-path class="w-4 h-4" />
Generar
</button>
</div>
@if(!$user)
<p class="text-xs text-gray-400">Mayúsculas, minúsculas, números y símbolo.</p>
@endif
@error('formPassword') <p class="text-error text-xs">{{ $message }}</p> @enderror
</div>
</div>
{{-- Estado --}}
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Estado <span class="text-error">*</span>
</label>
<div class="flex-1">
<select wire:model="userStatus" class="select select-bordered w-full max-w-xs">
<option value="active">Activo</option>
<option value="inactive">Inactivo</option>
<option value="suspended">Suspendido</option>
</select>
@error('userStatus') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
</div>
</div>
</div>
</div>
{{-- ══════════════════════════════════════════════════════════
3. CONTACTO
══════════════════════════════════════════════════════════ --}}
<div class="pb-6 mb-6 border-b border-base-200">
<h3 class="text-xs font-semibold text-gray-400 uppercase tracking-widest mb-4">
Contacto
</h3>
<div class="space-y-4">
{{-- Empresa --}}
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Empresa <span class="text-error">*</span>
</label>
<div class="flex-1">
<select wire:model.live="companyId" class="select select-bordered w-full">
<option value=""> Seleccionar empresa </option>
@foreach($companies as $company)
<option value="{{ $company->id }}">
{{ $company->apodo ?: $company->name }}
</option>
@endforeach
</select>
@error('companyId') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
</div>
</div>
{{-- Dirección --}}
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Dirección
</label>
<div class="flex-1 space-y-1.5">
<textarea wire:model="address" rows="2"
class="textarea textarea-bordered w-full"
placeholder="Calle, número, ciudad, CP, país"></textarea>
@if($companyId)
<button type="button" wire:click="copyCompanyAddress"
class="btn btn-xs btn-outline gap-1">
<x-heroicon-o-document-duplicate class="w-3.5 h-3.5" />
Copiar dirección de la empresa
</button>
@endif
</div>
</div>
{{-- Teléfono --}}
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Teléfono
</label>
<div class="flex-1">
<label class="input input-bordered flex items-center gap-2">
<x-heroicon-o-phone class="w-4 h-4 opacity-40 shrink-0" />
<input type="tel" wire:model="phone" class="grow"
placeholder="+34 600 123 456" />
</label>
</div>
</div>
{{-- Email --}}
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Email <span class="text-error">*</span>
</label>
<div class="flex-1">
<label class="input input-bordered flex items-center gap-2">
<x-heroicon-o-envelope class="w-4 h-4 opacity-40 shrink-0" />
<input type="email" wire:model="email" class="grow"
placeholder="ana@empresa.com" />
</label>
@error('email') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
</div>
</div>
</div>
</div>
{{-- ══════════════════════════════════════════════════════════
4. PERMISOS
══════════════════════════════════════════════════════════ --}}
<div class="pb-6 mb-6 border-b border-base-200">
<h3 class="text-xs font-semibold text-gray-400 uppercase tracking-widest mb-4">
Permisos
</h3>
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Rol <span class="text-error">*</span>
<p class="text-xs text-gray-400 font-normal mt-0.5">Define los permisos del usuario</p>
</label>
<div class="flex-1">
<select wire:model="formRole" class="select select-bordered w-full max-w-xs">
@foreach($roles as $role)
<option value="{{ $role->name }}">{{ $role->name }}</option>
@endforeach
</select>
@error('formRole') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
</div>
</div>
</div>
{{-- ══════════════════════════════════════════════════════════
5. NOTAS
══════════════════════════════════════════════════════════ --}}
<div class="pb-6 mb-6 border-b border-base-200">
<h3 class="text-xs font-semibold text-gray-400 uppercase tracking-widest mb-4">
Notas internas
</h3>
<div class="flex items-start gap-4">
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
Notas
<p class="text-xs text-gray-400 font-normal mt-0.5">Solo visible para administradores</p>
</label>
<div class="flex-1">
<textarea wire:model="notes" rows="4"
class="textarea textarea-bordered w-full"
placeholder="Observaciones, historial, información relevante…"></textarea>
</div>
</div>
</div>
{{-- ── Botones ───────────────────────────────────────────── --}}
<div class="flex items-center justify-between pt-2">
<a href="{{ route('admin.users') }}" class="btn btn-outline gap-1" wire:navigate>
<x-heroicon-o-x-mark class="w-4 h-4" />
Cancelar
</a>
<button type="submit" class="btn btn-primary gap-2"
wire:loading.attr="disabled" wire:target="save">
<span wire:loading wire:target="save" class="loading loading-spinner loading-sm"></span>
<x-heroicon-o-check class="w-4 h-4" />
{{ $user ? 'Guardar cambios' : 'Crear usuario' }}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>