fix(auth): register Spatie role/permission middleware + add missing #[Layout] (fixes post-login crash)
Login authenticated fine but the landing page crashed (so it looked like
'login doesn't work'):
- bootstrap/app.php didn't register Spatie's middleware aliases -> any route
with role:/permission: threw 'Target class [role] does not exist'.
Registered role / permission / role_or_permission.
- config/livewire.php absent -> default layout is the non-existent
components.layouts.app. ProjectList, PhaseProgress and ReportsDashboard
lacked #[Layout('layouts.app')] -> MissingLayoutException. Added it (the
other 10 routed components already had it).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,10 @@
|
|||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use Livewire\Attributes\Layout;
|
||||||
use App\Models\Phase;
|
use App\Models\Phase;
|
||||||
|
|
||||||
|
#[Layout('layouts.app')]
|
||||||
class PhaseProgress extends Component
|
class PhaseProgress extends Component
|
||||||
{
|
{
|
||||||
public Phase $phase;
|
public Phase $phase;
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ namespace App\Livewire;
|
|||||||
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Livewire\WithPagination;
|
use Livewire\WithPagination;
|
||||||
|
use Livewire\Attributes\Layout;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
#[Layout('layouts.app')]
|
||||||
class ProjectList extends Component
|
class ProjectList extends Component
|
||||||
{
|
{
|
||||||
use WithPagination;
|
use WithPagination;
|
||||||
|
|||||||
@@ -3,11 +3,13 @@
|
|||||||
namespace App\Livewire\Reports;
|
namespace App\Livewire\Reports;
|
||||||
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use Livewire\Attributes\Layout;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Phase;
|
use App\Models\Phase;
|
||||||
use App\Models\Inspection;
|
use App\Models\Inspection;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
#[Layout('layouts.app')]
|
||||||
class ReportsDashboard extends Component
|
class ReportsDashboard extends Component
|
||||||
{
|
{
|
||||||
public $dateRange = 'month'; // week, month, quarter, year
|
public $dateRange = 'month'; // week, month, quarter, year
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware): void {
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
$middleware->appendToGroup('web', \App\Http\Middleware\SetLocale::class);
|
$middleware->appendToGroup('web', \App\Http\Middleware\SetLocale::class);
|
||||||
|
|
||||||
|
// Spatie permission middleware aliases
|
||||||
|
$middleware->alias([
|
||||||
|
'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
|
||||||
|
'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
|
||||||
|
'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
|
||||||
|
]);
|
||||||
})
|
})
|
||||||
->withExceptions(function (Exceptions $exceptions): void {
|
->withExceptions(function (Exceptions $exceptions): void {
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,246 +1,246 @@
|
|||||||
<div>
|
<div>
|
||||||
<x-slot name="header">
|
<x-slot name="header">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<a href="{{ route('companies.manage') }}" class="btn btn-ghost btn-sm px-2" wire:navigate>
|
<a href="{{ route('companies.manage') }}" class="btn btn-ghost btn-sm px-2" wire:navigate>
|
||||||
<x-heroicon-o-arrow-left class="w-4 h-4" />
|
<x-heroicon-o-arrow-left class="w-4 h-4" />
|
||||||
</a>
|
</a>
|
||||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||||
{{ $company ? 'Editar empresa: ' . $company->name : 'Nueva empresa' }}
|
{{ $company ? 'Editar empresa: ' . $company->name : 'Nueva empresa' }}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</x-slot>
|
</x-slot>
|
||||||
|
|
||||||
<div class="py-8">
|
<div class="py-8">
|
||||||
<div class="max-w-3xl mx-auto sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
|
|
||||||
@if(session('notify'))
|
@if(session('notify'))
|
||||||
<div class="alert alert-success mb-4">{{ session('notify') }}</div>
|
<div class="alert alert-success mb-4">{{ session('notify') }}</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body p-8">
|
<div class="card-body p-8">
|
||||||
|
|
||||||
<form wire:submit.prevent="save" class="space-y-0">
|
<form wire:submit.prevent="save" class="space-y-0">
|
||||||
|
|
||||||
@if($errors->any())
|
@if($errors->any())
|
||||||
<div class="alert alert-error text-sm mb-6">
|
<div class="alert alert-error text-sm mb-6">
|
||||||
<x-heroicon-o-exclamation-circle class="w-5 h-5 shrink-0" />
|
<x-heroicon-o-exclamation-circle class="w-5 h-5 shrink-0" />
|
||||||
<ul class="list-disc pl-3 space-y-0.5">
|
<ul class="list-disc pl-3 space-y-0.5">
|
||||||
@foreach($errors->all() as $e) <li>{{ $e }}</li> @endforeach
|
@foreach($errors->all() as $e) <li>{{ $e }}</li> @endforeach
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
{{-- ── Macro para fila de formulario horizontal ──────────── --}}
|
|
||||||
{{-- Patrón: flex row, label w-48 shrink-0, campo flex-1 --}}
|
|
||||||
|
|
||||||
{{-- ── Sección: Identificació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">
|
|
||||||
Identificación
|
|
||||||
</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">
|
|
||||||
Nombre registrado <span class="text-error">*</span>
|
|
||||||
</label>
|
|
||||||
<div class="flex-1">
|
|
||||||
<input type="text" wire:model="name"
|
|
||||||
class="input input-bordered w-full"
|
|
||||||
placeholder="Constructora Ejemplo, S.L." />
|
|
||||||
@error('name') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
@endif
|
||||||
|
|
||||||
<div class="flex items-start gap-4">
|
{{-- ── Macro para fila de formulario horizontal ──────────── --}}
|
||||||
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
{{-- Patrón: flex row, label w-48 shrink-0, campo flex-1 --}}
|
||||||
Apodo / comercial
|
|
||||||
</label>
|
|
||||||
<div class="flex-1">
|
|
||||||
<input type="text" wire:model="apodo"
|
|
||||||
class="input input-bordered w-full"
|
|
||||||
placeholder="Ejemplo Constr." />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-start gap-4">
|
{{-- ── Sección: Identificación ──────────────────────────── --}}
|
||||||
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
<div class="pb-6 mb-6 border-b border-base-200">
|
||||||
NIF / CIF / Tax ID
|
<h3 class="text-xs font-semibold text-gray-400 uppercase tracking-widest mb-4">
|
||||||
</label>
|
Identificación
|
||||||
<div class="flex-1">
|
</h3>
|
||||||
<input type="text" wire:model="tax_id"
|
<div class="space-y-4">
|
||||||
class="input input-bordered w-full"
|
|
||||||
placeholder="B12345678" />
|
|
||||||
@error('tax_id') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-start gap-4">
|
<div class="flex items-start gap-4">
|
||||||
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
||||||
Tipo de empresa <span class="text-error">*</span>
|
Nombre registrado <span class="text-error">*</span>
|
||||||
</label>
|
</label>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<select wire:model="type" class="select select-bordered w-full">
|
<input type="text" wire:model="name"
|
||||||
<option value="owner">Promotor / Propietario</option>
|
class="input input-bordered w-full"
|
||||||
<option value="constructor">Constructor principal</option>
|
placeholder="Constructora Ejemplo, S.L." />
|
||||||
<option value="subcontractor">Subcontratista</option>
|
@error('name') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
|
||||||
<option value="consultant">Consultor / Ingeniería</option>
|
</div>
|
||||||
<option value="supplier">Proveedor</option>
|
|
||||||
<option value="other">Otro</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">
|
|
||||||
Estado <span class="text-error">*</span>
|
|
||||||
</label>
|
|
||||||
<div class="flex-1">
|
|
||||||
<select wire:model="estado" class="select select-bordered w-full max-w-xs">
|
|
||||||
<option value="activo">Activo</option>
|
|
||||||
<option value="inactivo">Inactivo</option>
|
|
||||||
<option value="suspendido">Suspendido</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- ── Sección: 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">
|
|
||||||
|
|
||||||
<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">
|
|
||||||
<textarea wire:model="address" rows="2"
|
|
||||||
class="textarea textarea-bordered w-full"
|
|
||||||
placeholder="Calle, número, ciudad, CP, país"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<div class="flex items-start gap-4">
|
|
||||||
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
|
||||||
Email
|
|
||||||
</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="contacto@empresa.com" />
|
|
||||||
</label>
|
|
||||||
@error('email') <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">
|
|
||||||
Sitio web
|
|
||||||
</label>
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="input input-bordered flex items-center gap-2">
|
|
||||||
<x-heroicon-o-globe-alt class="w-4 h-4 opacity-40 shrink-0" />
|
|
||||||
<input type="url" wire:model="website" class="grow"
|
|
||||||
placeholder="https://www.empresa.com" />
|
|
||||||
</label>
|
|
||||||
@error('website') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- ── Sección: Logo ─────────────────────────────────────── --}}
|
|
||||||
<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">
|
|
||||||
Logo
|
|
||||||
</h3>
|
|
||||||
<div class="flex items-start gap-4">
|
|
||||||
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
|
||||||
{{ $company?->logo_path ? 'Reemplazar logo' : 'Subir logo' }}
|
|
||||||
<p class="text-xs text-gray-400 font-normal mt-0.5">PNG / JPG, máx. 2 MB</p>
|
|
||||||
</label>
|
|
||||||
<div class="flex-1 flex items-start gap-4">
|
|
||||||
{{-- Preview --}}
|
|
||||||
@if($logo)
|
|
||||||
<img src="{{ $logo->temporaryUrl() }}" alt="Preview"
|
|
||||||
class="w-16 h-16 object-contain border border-base-300 rounded-lg shrink-0" />
|
|
||||||
@elseif($company?->logo_path && \Illuminate\Support\Facades\Storage::disk('public')->exists($company->logo_path))
|
|
||||||
<img src="{{ \Illuminate\Support\Facades\Storage::disk('public')->url($company->logo_path) }}"
|
|
||||||
alt="Logo actual"
|
|
||||||
class="w-16 h-16 object-contain border border-base-300 rounded-lg shrink-0" />
|
|
||||||
@else
|
|
||||||
<div class="w-16 h-16 bg-base-200 rounded-lg flex items-center justify-center shrink-0">
|
|
||||||
<x-heroicon-o-building-office class="w-7 h-7 opacity-30" />
|
|
||||||
</div>
|
</div>
|
||||||
@endif
|
|
||||||
<div class="flex-1">
|
<div class="flex items-start gap-4">
|
||||||
<input type="file" wire:model="logo" accept="image/*"
|
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
||||||
class="file-input file-input-bordered w-full" />
|
Apodo / comercial
|
||||||
<div wire:loading wire:target="logo" class="text-xs text-info mt-1">Subiendo…</div>
|
</label>
|
||||||
@error('logo') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
|
<div class="flex-1">
|
||||||
|
<input type="text" wire:model="apodo"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
placeholder="Ejemplo Constr." />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-start gap-4">
|
||||||
|
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
||||||
|
NIF / CIF / Tax ID
|
||||||
|
</label>
|
||||||
|
<div class="flex-1">
|
||||||
|
<input type="text" wire:model="tax_id"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
placeholder="B12345678" />
|
||||||
|
@error('tax_id') <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">
|
||||||
|
Tipo de empresa <span class="text-error">*</span>
|
||||||
|
</label>
|
||||||
|
<div class="flex-1">
|
||||||
|
<select wire:model="type" class="select select-bordered w-full">
|
||||||
|
<option value="owner">Promotor / Propietario</option>
|
||||||
|
<option value="constructor">Constructor principal</option>
|
||||||
|
<option value="subcontractor">Subcontratista</option>
|
||||||
|
<option value="consultant">Consultor / Ingeniería</option>
|
||||||
|
<option value="supplier">Proveedor</option>
|
||||||
|
<option value="other">Otro</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">
|
||||||
|
Estado <span class="text-error">*</span>
|
||||||
|
</label>
|
||||||
|
<div class="flex-1">
|
||||||
|
<select wire:model="estado" class="select select-bordered w-full max-w-xs">
|
||||||
|
<option value="activo">Activo</option>
|
||||||
|
<option value="inactivo">Inactivo</option>
|
||||||
|
<option value="suspendido">Suspendido</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- ── Sección: Notas ────────────────────────────────────── --}}
|
{{-- ── Sección: Contacto ─────────────────────────────────── --}}
|
||||||
<div class="pb-6 mb-6 border-b border-base-200">
|
<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">
|
<h3 class="text-xs font-semibold text-gray-400 uppercase tracking-widest mb-4">
|
||||||
Notas internas
|
Contacto
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex items-start gap-4">
|
<div class="space-y-4">
|
||||||
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
|
||||||
Observaciones
|
<div class="flex items-start gap-4">
|
||||||
<p class="text-xs text-gray-400 font-normal mt-0.5">Información interna</p>
|
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
||||||
</label>
|
Dirección
|
||||||
<div class="flex-1">
|
</label>
|
||||||
<textarea wire:model="notes" rows="3"
|
<div class="flex-1">
|
||||||
class="textarea textarea-bordered w-full"
|
<textarea wire:model="address" rows="2"
|
||||||
placeholder="Condiciones especiales, observaciones…"></textarea>
|
class="textarea textarea-bordered w-full"
|
||||||
|
placeholder="Calle, número, ciudad, CP, país"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<div class="flex items-start gap-4">
|
||||||
|
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
||||||
|
Email
|
||||||
|
</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="contacto@empresa.com" />
|
||||||
|
</label>
|
||||||
|
@error('email') <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">
|
||||||
|
Sitio web
|
||||||
|
</label>
|
||||||
|
<div class="flex-1">
|
||||||
|
<label class="input input-bordered flex items-center gap-2">
|
||||||
|
<x-heroicon-o-globe-alt class="w-4 h-4 opacity-40 shrink-0" />
|
||||||
|
<input type="url" wire:model="website" class="grow"
|
||||||
|
placeholder="https://www.empresa.com" />
|
||||||
|
</label>
|
||||||
|
@error('website') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- ── Botones ───────────────────────────────────────────── --}}
|
{{-- ── Sección: Logo ─────────────────────────────────────── --}}
|
||||||
<div class="flex items-center justify-between pt-2">
|
<div class="pb-6 mb-6 border-b border-base-200">
|
||||||
<a href="{{ route('companies.manage') }}" class="btn btn-outline gap-1" wire:navigate>
|
<h3 class="text-xs font-semibold text-gray-400 uppercase tracking-widest mb-4">
|
||||||
<x-heroicon-o-x-mark class="w-4 h-4" />
|
Logo
|
||||||
Cancelar
|
</h3>
|
||||||
</a>
|
<div class="flex items-start gap-4">
|
||||||
<button type="submit" class="btn btn-primary gap-2"
|
<label class="w-48 shrink-0 pt-2 text-sm font-medium text-gray-700">
|
||||||
wire:loading.attr="disabled" wire:target="save">
|
{{ $company?->logo_path ? 'Reemplazar logo' : 'Subir logo' }}
|
||||||
<span wire:loading wire:target="save" class="loading loading-spinner loading-sm"></span>
|
<p class="text-xs text-gray-400 font-normal mt-0.5">PNG / JPG, máx. 2 MB</p>
|
||||||
<x-heroicon-o-check class="w-4 h-4" />
|
</label>
|
||||||
{{ $company ? 'Guardar cambios' : 'Crear empresa' }}
|
<div class="flex-1 flex items-start gap-4">
|
||||||
</button>
|
{{-- Preview --}}
|
||||||
</div>
|
@if($logo)
|
||||||
|
<img src="{{ $logo->temporaryUrl() }}" alt="Preview"
|
||||||
|
class="w-16 h-16 object-contain border border-base-300 rounded-lg shrink-0" />
|
||||||
|
@elseif($company?->logo_path && \Illuminate\Support\Facades\Storage::disk('public')->exists($company->logo_path))
|
||||||
|
<img src="{{ \Illuminate\Support\Facades\Storage::disk('public')->url($company->logo_path) }}"
|
||||||
|
alt="Logo actual"
|
||||||
|
class="w-16 h-16 object-contain border border-base-300 rounded-lg shrink-0" />
|
||||||
|
@else
|
||||||
|
<div class="w-16 h-16 bg-base-200 rounded-lg flex items-center justify-center shrink-0">
|
||||||
|
<x-heroicon-o-building-office class="w-7 h-7 opacity-30" />
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<div class="flex-1">
|
||||||
|
<input type="file" wire:model="logo" accept="image/*"
|
||||||
|
class="file-input file-input-bordered w-full" />
|
||||||
|
<div wire:loading wire:target="logo" class="text-xs text-info mt-1">Subiendo…</div>
|
||||||
|
@error('logo') <p class="text-error text-xs mt-1">{{ $message }}</p> @enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</form>
|
{{-- ── Sección: 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">
|
||||||
|
Observaciones
|
||||||
|
<p class="text-xs text-gray-400 font-normal mt-0.5">Información interna</p>
|
||||||
|
</label>
|
||||||
|
<div class="flex-1">
|
||||||
|
<textarea wire:model="notes" rows="3"
|
||||||
|
class="textarea textarea-bordered w-full"
|
||||||
|
placeholder="Condiciones especiales, observaciones…"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- ── Botones ───────────────────────────────────────────── --}}
|
||||||
|
<div class="flex items-center justify-between pt-2">
|
||||||
|
<a href="{{ route('companies.manage') }}" 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" />
|
||||||
|
{{ $company ? 'Guardar cambios' : 'Crear empresa' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="max-w-4xl mx-auto p-4">
|
<div class="max-w-7xl mx-auto p-4">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<h1 class="text-2xl font-bold">{{ $project ? __('Edit Project') : __('New Project') }}</h1>
|
<h1 class="text-2xl font-bold">{{ $project ? __('Edit Project') : __('New Project') }}</h1>
|
||||||
<a href="{{ route('projects.index') }}" class="btn btn-ghost btn-sm gap-1" wire:navigate>
|
<a href="{{ route('projects.index') }}" class="btn btn-ghost btn-sm gap-1" wire:navigate>
|
||||||
|
|||||||
Reference in New Issue
Block a user