Agregue middleware a productos Destroy y Edit. Y cambios en la vista de stock.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<x-layout title="Lauck - Stock">
|
||||
|
||||
|
||||
<x-section-header subtitle="Gestión de Inventario" title="Listado de " highlight="Productos" />
|
||||
|
||||
<!-- Mensajes de feedback -->
|
||||
@@ -7,25 +7,28 @@
|
||||
|
||||
<!-- Barra de Herramientas (Buscador + Botones) -->
|
||||
<div class="w-full flex flex-col xl:flex-row justify-between items-start xl:items-center gap-4 mb-6">
|
||||
|
||||
|
||||
<!-- Buscador y Filtros -->
|
||||
<form action="{{ route('productos.index') }}" method="GET" class="w-full xl:w-4/5 flex flex-col md:flex-row gap-3">
|
||||
|
||||
<form action="{{ route('productos.index') }}" method="GET"
|
||||
class="w-full xl:w-4/5 flex flex-col md:flex-row gap-3">
|
||||
|
||||
<!-- 1. Buscador por Texto -->
|
||||
<div class="relative w-full md:w-2/5">
|
||||
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">
|
||||
<svg class="w-4 h-4 text-gray-600 dark:text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"/>
|
||||
<svg class="w-4 h-4 text-gray-600 dark:text-gray-500" aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<input type="text" name="search" value="{{ request('search') }}"
|
||||
class="block w-full p-3 ps-10 text-sm text-black dark:text-white border border-neutral-400 dark:border-neutral-700 rounded-lg bg-neutral-200 dark:bg-neutral-800 placeholder-gray-600 dark:placeholder-gray-500 focus:ring-neon-lime focus:border-neon-lime"
|
||||
<input type="text" name="search" value="{{ request('search') }}"
|
||||
class="block w-full p-3 ps-10 text-sm text-black dark:text-white border border-neutral-400 dark:border-neutral-700 rounded-lg bg-neutral-200 dark:bg-neutral-800 placeholder-gray-600 dark:placeholder-gray-500 focus:ring-neon-lime focus:border-neon-lime"
|
||||
placeholder="Buscar por nombre">
|
||||
</div>
|
||||
|
||||
<!-- 2. Filtro de Categoría (Tipo) -->
|
||||
<div class="w-full md:w-1/4">
|
||||
<select name="type" onchange="this.form.submit()"
|
||||
<select name="type" onchange="this.form.submit()"
|
||||
class="block w-full p-3 text-sm text-black dark:text-white border border-neutral-300 dark:border-neutral-700 rounded-lg bg-neutral-200 dark:bg-neutral-800 focus:ring-neon-lime focus:border-neon-lime cursor-pointer">
|
||||
<option value="">Todas las Categorías</option>
|
||||
<option value="bike" {{ request('type') == 'bike' ? 'selected' : '' }}>Bicicletas</option>
|
||||
@@ -42,22 +45,27 @@
|
||||
|
||||
<!-- 3. Filtro de Estado de Stock -->
|
||||
<div class="w-full md:w-1/4">
|
||||
<select name="stock_status" onchange="this.form.submit()"
|
||||
<select name="stock_status" onchange="this.form.submit()"
|
||||
class="block w-full p-3 text-sm text-black dark:text-white border border-neutral-300 dark:border-neutral-700 rounded-lg bg-neutral-200 dark:bg-neutral-800 focus:ring-neon-lime focus:border-neon-lime cursor-pointer">
|
||||
<option value="">Cualquier Stock</option>
|
||||
<option value="low" {{ request('stock_status') == 'low' ? 'selected' : '' }} class="text-red-600 dark:text-red-300 font-semibold">Stock en Alerta</option>
|
||||
<option value="medium" {{ request('stock_status') == 'medium' ? 'selected' : '' }} class="text-yellow-600 dark:text-yellow-300 font-semibold">Stock Bajo</option>
|
||||
<option value="ok" {{ request('stock_status') == 'ok' ? 'selected' : '' }} class="text-green-600 dark:text-green-300 font-semibold">Stock Normal</option>
|
||||
<option value="low" {{ request('stock_status') == 'low' ? 'selected' : '' }}
|
||||
class="text-red-600 dark:text-red-300 font-semibold">Stock en Alerta</option>
|
||||
<option value="medium" {{ request('stock_status') == 'medium' ? 'selected' : '' }}
|
||||
class="text-yellow-600 dark:text-yellow-300 font-semibold">Stock Bajo</option>
|
||||
<option value="ok" {{ request('stock_status') == 'ok' ? 'selected' : '' }}
|
||||
class="text-green-600 dark:text-green-300 font-semibold">Stock Normal</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Botón Limpiar Filtros -->
|
||||
@if(request('search') || request('type') || request('stock_status'))
|
||||
@if (request('search') || request('type') || request('stock_status'))
|
||||
<div class="w-full md:w-auto flex">
|
||||
<a href="{{ route('productos.index') }}" title="Limpiar Filtros"
|
||||
class="flex items-center justify-center p-3 text-sm font-bold text-red-600 dark:text-red-400 bg-red-100 dark:bg-red-900/30 rounded-lg hover:bg-red-200 dark:hover:bg-red-900/50 border border-red-200 dark:border-red-800 transition-colors">
|
||||
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18 17.94 6M18 18 6.06 6"/>
|
||||
<a href="{{ route('productos.index') }}" title="Limpiar Filtros"
|
||||
class="flex items-center justify-center p-3 text-sm font-bold text-red-600 dark:text-red-400 bg-red-100 dark:bg-red-900/30 rounded-lg hover:bg-red-200 dark:hover:bg-red-900/50 border border-red-200 dark:border-red-800 transition-colors">
|
||||
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M6 18 17.94 6M18 18 6.06 6" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
@@ -65,7 +73,8 @@
|
||||
</form>
|
||||
|
||||
<!-- Botón Nuevo -->
|
||||
<a href="{{ route('productos.create') }}" class="w-full xl:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
||||
<a href="{{ route('productos.create') }}"
|
||||
class="w-full xl:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
||||
+ Nuevo Producto
|
||||
</a>
|
||||
</div>
|
||||
@@ -73,7 +82,8 @@
|
||||
<!-- Tabla de Productos -->
|
||||
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full">
|
||||
<table class="w-full text-sm text-left rtl:text-right text-neutral-900 dark:text-white">
|
||||
<thead class="text-xs text-neutral-800 dark:text-gray-300 uppercase bg-gray-400 dark:bg-neutral-800 border-b border-gray-300 dark:border-neutral-700">
|
||||
<thead
|
||||
class="text-xs text-neutral-800 dark:text-gray-300 uppercase bg-gray-400 dark:bg-neutral-800 border-b border-gray-300 dark:border-neutral-700">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3">Producto</th>
|
||||
<th scope="col" class="px-6 py-3">Tipo</th>
|
||||
@@ -84,61 +94,108 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($products as $product)
|
||||
<tr class="bg-gray-200/50 dark:bg-neutral-900/50 border-b border-gray-400 dark:border-neutral-800 hover:bg-gray-400 hover:dark:bg-neutral-800 transition-colors group">
|
||||
<td class="px-6 py-4 font-medium whitespace-nowrap">
|
||||
<div class="text-base font-bold">{{ $product->name }}</div>
|
||||
<div class="text-xs text-gray-600 dark:text-gray-400 font-mono">{{ $product->sku ?? 'Sin SKU' }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
@if($product->type === 'bike') <x-ui.badge color="neon">Bicicleta</x-ui.badge>
|
||||
@elseif($product->type === 'clothing') <x-ui.badge color="blue">Indumentaria</x-ui.badge>
|
||||
@elseif($product->type === 'spare') <x-ui.badge color="gray">Repuesto</x-ui.badge>
|
||||
@elseif($product->type === 'children') <x-ui.badge color="pink">Infantil</x-ui.badge>
|
||||
@elseif($product->type === 'rollers') <x-ui.badge color="purple">Rollers</x-ui.badge>
|
||||
@elseif($product->type === 'skate') <x-ui.badge color="orange">Skate</x-ui.badge>
|
||||
@else <x-ui.badge color="yellow">Accesorio / Otro</x-ui.badge> @endif
|
||||
</td>
|
||||
<td class="px-6 py-4 font-mono">
|
||||
${{ number_format($product->price, 2) }}
|
||||
</td>
|
||||
<td class="px-6 py-4 text-center">
|
||||
@if($product->stock_quantity < $product->min_stock_alert)
|
||||
<x-ui.badge color="red">{{ $product->stock_quantity }}</x-ui.badge>
|
||||
@elseif($product->stock_quantity <= $product->min_stock_alert+5)
|
||||
<x-ui.badge color="yellow">{{ $product->stock_quantity }}</x-ui.badge>
|
||||
@else
|
||||
<x-ui.badge color="green">{{ $product->stock_quantity }}</x-ui.badge>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-6 py-4 text-right flex items-center gap-2 justify-end">
|
||||
<a href="{{ route('productos.show', $product) }}" title="Ver Mas" class="font-semibold p-2 text-green-700 dark:text-green-400 border-2 border-green-700 rounded-lg hover:bg-green-700 dark:hover:bg-green-600 dark:hover:border-green-600 hover:text-white dark:hover:text-white transition-colors">
|
||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-width="2" d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z"/>
|
||||
<path stroke="currentColor" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="{{ route('productos.edit', $product) }}" title="Editar" class="font-semibold p-2 text-blue-800 dark:text-blue-400 border-2 border-blue-800 rounded-lg hover:bg-blue-800 hover:text-white dark:hover:text-white transition-colors">
|
||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<form action="{{route('productos.destroy',$product)}}" method="post">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button title="Eliminar" type="submit" class="w-full sm:w-auto p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
||||
<tr
|
||||
class="bg-gray-200/50 dark:bg-neutral-900/50 border-b border-gray-400 dark:border-neutral-800 hover:bg-gray-400 hover:dark:bg-neutral-800 transition-colors group">
|
||||
<td class="px-6 py-4 font-medium whitespace-nowrap">
|
||||
<div class="text-base font-bold">{{ $product->name }}</div>
|
||||
<div class="text-xs text-gray-600 dark:text-gray-400 font-mono">
|
||||
{{ $product->sku ?? 'Sin SKU' }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
@if ($product->type === 'bike')
|
||||
<x-ui.badge color="neon">Bicicleta</x-ui.badge>
|
||||
@elseif($product->type === 'clothing')
|
||||
<x-ui.badge color="blue">Indumentaria</x-ui.badge>
|
||||
@elseif($product->type === 'spare')
|
||||
<x-ui.badge color="gray">Repuesto</x-ui.badge>
|
||||
@elseif($product->type === 'children')
|
||||
<x-ui.badge color="pink">Infantil</x-ui.badge>
|
||||
@elseif($product->type === 'rollers')
|
||||
<x-ui.badge color="purple">Rollers</x-ui.badge>
|
||||
@elseif($product->type === 'skate')
|
||||
<x-ui.badge color="orange">Skate</x-ui.badge>
|
||||
@else
|
||||
<x-ui.badge color="yellow">Accesorio / Otro</x-ui.badge>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-6 py-4 font-mono">
|
||||
${{ number_format($product->price, 2) }}
|
||||
</td>
|
||||
<td class="px-6 py-4 text-center">
|
||||
@if ($product->stock_quantity < $product->min_stock_alert)
|
||||
<x-ui.badge color="red">{{ $product->stock_quantity }}</x-ui.badge>
|
||||
@elseif($product->stock_quantity <= $product->min_stock_alert + 5)
|
||||
<x-ui.badge color="yellow">{{ $product->stock_quantity }}</x-ui.badge>
|
||||
@else
|
||||
<x-ui.badge color="green">{{ $product->stock_quantity }}</x-ui.badge>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-6 py-4 text-right flex items-center gap-2 justify-end">
|
||||
<a href="{{ route('productos.show', $product) }}" title="Ver Mas"
|
||||
class="font-semibold p-2 text-green-700 dark:text-green-400 border-2 border-green-700 rounded-lg hover:bg-green-700 dark:hover:bg-green-600 dark:hover:border-green-600 hover:text-white dark:hover:text-white transition-colors">
|
||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-width="2"
|
||||
d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z" />
|
||||
<path stroke="currentColor" stroke-width="2"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</a>
|
||||
|
||||
@php
|
||||
$isAdmin = auth()->user()?->role === 'admin';
|
||||
$classes = $isAdmin
|
||||
? 'text-blue-800 border-blue-800 hover:bg-blue-800 hover:text-white'
|
||||
: 'border-black-400 text-black-400 opacity-50 cursor-not-allowed dark:border-gray-400 dark:text-gray-400';
|
||||
@endphp
|
||||
|
||||
<a @if ($isAdmin) href="{{ route('productos.edit', $product) }}" @endif
|
||||
title="Editar"
|
||||
class="font-semibold p-2 border-2 rounded-lg transition-colors {{ $classes }}">
|
||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z" />
|
||||
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
@if (auth()->user()?->role === 'admin')
|
||||
<form action="{{ route('productos.destroy', $product) }}" method="post"
|
||||
class="inline">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button title="Eliminar" type="submit"
|
||||
onclick="return confirm('¿Estás seguro de eliminar este producto?')"
|
||||
class="w-full sm:w-auto p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round"
|
||||
stroke-linejoin="round" stroke-width="2"
|
||||
d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z" />
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<button title="Eliminar" disabled
|
||||
class="w-full sm:w-auto p-2 border-2 dark:border-gray-400 dark:text-gray-400 border-black-400 text-black-400 rounded-lg cursor-not-allowed opacity-50">
|
||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z" />
|
||||
</svg>
|
||||
</button>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="5" class="px-6 py-10 text-center font-semibold">
|
||||
No se encontraron productos.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5" class="px-6 py-10 text-center font-semibold">
|
||||
No se encontraron productos.
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -148,4 +205,4 @@
|
||||
<div class="mt-4 w-full">
|
||||
{{ $products->links() }}
|
||||
</div>
|
||||
</x-layout>
|
||||
</x-layout>
|
||||
|
||||
Reference in New Issue
Block a user