Agregue middleware a productos Destroy y Edit. Y cambios en la vista de stock.

This commit is contained in:
2026-04-10 16:15:01 -03:00
parent cf0b40d79e
commit 00247399a4
4 changed files with 176 additions and 87 deletions
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CheckAdmin //
{
public function handle(Request $request, Closure $next): Response
{
if (auth()->check() && auth()->user()->role === 'admin') {
return $next($request);
}
abort(403, 'No tienes permiso para entrar aquí.');
}
}
+3
View File
@@ -12,6 +12,9 @@ return Application::configure(basePath: dirname(__DIR__))
) )
->withMiddleware(function (Middleware $middleware): void { ->withMiddleware(function (Middleware $middleware): void {
// //
$middleware->alias([
'admin' => \App\Http\Middleware\CheckAdmin::class,
]);
}) })
->withExceptions(function (Exceptions $exceptions): void { ->withExceptions(function (Exceptions $exceptions): void {
// //
+131 -74
View File
@@ -1,5 +1,5 @@
<x-layout title="Lauck - Stock"> <x-layout title="Lauck - Stock">
<x-section-header subtitle="Gestión de Inventario" title="Listado de " highlight="Productos" /> <x-section-header subtitle="Gestión de Inventario" title="Listado de " highlight="Productos" />
<!-- Mensajes de feedback --> <!-- Mensajes de feedback -->
@@ -7,25 +7,28 @@
<!-- Barra de Herramientas (Buscador + Botones) --> <!-- 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"> <div class="w-full flex flex-col xl:flex-row justify-between items-start xl:items-center gap-4 mb-6">
<!-- Buscador y Filtros --> <!-- 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 --> <!-- 1. Buscador por Texto -->
<div class="relative w-full md:w-2/5"> <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"> <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"> <svg class="w-4 h-4 text-gray-600 dark:text-gray-500" aria-hidden="true"
<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"/> 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> </svg>
</div> </div>
<input type="text" name="search" value="{{ request('search') }}" <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" 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"> placeholder="Buscar por nombre">
</div> </div>
<!-- 2. Filtro de Categoría (Tipo) --> <!-- 2. Filtro de Categoría (Tipo) -->
<div class="w-full md:w-1/4"> <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"> 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="">Todas las Categorías</option>
<option value="bike" {{ request('type') == 'bike' ? 'selected' : '' }}>Bicicletas</option> <option value="bike" {{ request('type') == 'bike' ? 'selected' : '' }}>Bicicletas</option>
@@ -42,22 +45,27 @@
<!-- 3. Filtro de Estado de Stock --> <!-- 3. Filtro de Estado de Stock -->
<div class="w-full md:w-1/4"> <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"> 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="">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="low" {{ request('stock_status') == 'low' ? 'selected' : '' }}
<option value="medium" {{ request('stock_status') == 'medium' ? 'selected' : '' }} class="text-yellow-600 dark:text-yellow-300 font-semibold">Stock Bajo</option> class="text-red-600 dark:text-red-300 font-semibold">Stock en Alerta</option>
<option value="ok" {{ request('stock_status') == 'ok' ? 'selected' : '' }} class="text-green-600 dark:text-green-300 font-semibold">Stock Normal</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> </select>
</div> </div>
<!-- Botón Limpiar Filtros --> <!-- 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"> <div class="w-full md:w-auto flex">
<a href="{{ route('productos.index') }}" title="Limpiar Filtros" <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"> 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"> <svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24"
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18 17.94 6M18 18 6.06 6"/> 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> </svg>
</a> </a>
</div> </div>
@@ -65,7 +73,8 @@
</form> </form>
<!-- Botón Nuevo --> <!-- 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 + Nuevo Producto
</a> </a>
</div> </div>
@@ -73,7 +82,8 @@
<!-- Tabla de Productos --> <!-- Tabla de Productos -->
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full"> <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"> <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> <tr>
<th scope="col" class="px-6 py-3">Producto</th> <th scope="col" class="px-6 py-3">Producto</th>
<th scope="col" class="px-6 py-3">Tipo</th> <th scope="col" class="px-6 py-3">Tipo</th>
@@ -84,61 +94,108 @@
</thead> </thead>
<tbody> <tbody>
@forelse($products as $product) @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"> <tr
<td class="px-6 py-4 font-medium whitespace-nowrap"> 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">
<div class="text-base font-bold">{{ $product->name }}</div> <td class="px-6 py-4 font-medium whitespace-nowrap">
<div class="text-xs text-gray-600 dark:text-gray-400 font-mono">{{ $product->sku ?? 'Sin SKU' }}</div> <div class="text-base font-bold">{{ $product->name }}</div>
</td> <div class="text-xs text-gray-600 dark:text-gray-400 font-mono">
<td class="px-6 py-4"> {{ $product->sku ?? 'Sin SKU' }}</div>
@if($product->type === 'bike') <x-ui.badge color="neon">Bicicleta</x-ui.badge> </td>
@elseif($product->type === 'clothing') <x-ui.badge color="blue">Indumentaria</x-ui.badge> <td class="px-6 py-4">
@elseif($product->type === 'spare') <x-ui.badge color="gray">Repuesto</x-ui.badge> @if ($product->type === 'bike')
@elseif($product->type === 'children') <x-ui.badge color="pink">Infantil</x-ui.badge> <x-ui.badge color="neon">Bicicleta</x-ui.badge>
@elseif($product->type === 'rollers') <x-ui.badge color="purple">Rollers</x-ui.badge> @elseif($product->type === 'clothing')
@elseif($product->type === 'skate') <x-ui.badge color="orange">Skate</x-ui.badge> <x-ui.badge color="blue">Indumentaria</x-ui.badge>
@else <x-ui.badge color="yellow">Accesorio / Otro</x-ui.badge> @endif @elseif($product->type === 'spare')
</td> <x-ui.badge color="gray">Repuesto</x-ui.badge>
<td class="px-6 py-4 font-mono"> @elseif($product->type === 'children')
${{ number_format($product->price, 2) }} <x-ui.badge color="pink">Infantil</x-ui.badge>
</td> @elseif($product->type === 'rollers')
<td class="px-6 py-4 text-center"> <x-ui.badge color="purple">Rollers</x-ui.badge>
@if($product->stock_quantity < $product->min_stock_alert) @elseif($product->type === 'skate')
<x-ui.badge color="red">{{ $product->stock_quantity }}</x-ui.badge> <x-ui.badge color="orange">Skate</x-ui.badge>
@elseif($product->stock_quantity <= $product->min_stock_alert+5) @else
<x-ui.badge color="yellow">{{ $product->stock_quantity }}</x-ui.badge> <x-ui.badge color="yellow">Accesorio / Otro</x-ui.badge>
@else @endif
<x-ui.badge color="green">{{ $product->stock_quantity }}</x-ui.badge> </td>
@endif <td class="px-6 py-4 font-mono">
</td> ${{ number_format($product->price, 2) }}
<td class="px-6 py-4 text-right flex items-center gap-2 justify-end"> </td>
<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"> <td class="px-6 py-4 text-center">
<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"> @if ($product->stock_quantity < $product->min_stock_alert)
<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"/> <x-ui.badge color="red">{{ $product->stock_quantity }}</x-ui.badge>
<path stroke="currentColor" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/> @elseif($product->stock_quantity <= $product->min_stock_alert + 5)
</svg> <x-ui.badge color="yellow">{{ $product->stock_quantity }}</x-ui.badge>
</a> @else
<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"> <x-ui.badge color="green">{{ $product->stock_quantity }}</x-ui.badge>
<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"> @endif
<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"/> </td>
</svg> <td class="px-6 py-4 text-right flex items-center gap-2 justify-end">
</a> <a href="{{ route('productos.show', $product) }}" title="Ver Mas"
<form action="{{route('productos.destroy',$product)}}" method="post"> 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">
@csrf <svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
@method('DELETE') width="24" height="24" fill="none" viewBox="0 0 24 24">
<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"> <path stroke="currentColor" stroke-width="2"
<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"> 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-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"/> <path stroke="currentColor" stroke-width="2"
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
</svg> </svg>
</button> </a>
</form>
</td> @php
</tr> $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 @empty
<tr> <tr>
<td colspan="5" class="px-6 py-10 text-center font-semibold"> <td colspan="5" class="px-6 py-10 text-center font-semibold">
No se encontraron productos. No se encontraron productos.
</td> </td>
</tr> </tr>
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
@@ -148,4 +205,4 @@
<div class="mt-4 w-full"> <div class="mt-4 w-full">
{{ $products->links() }} {{ $products->links() }}
</div> </div>
</x-layout> </x-layout>
+23 -13
View File
@@ -16,41 +16,51 @@ use App\Models\Product;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Session;
Route::get('/',HomeController::class); // --- RUTAS PÚBLICAS (Cualquiera accede) ---
Route::get('/', HomeController::class);
// Route::get('/catalogo', [CatalogoController::class,'catalogo'])->name('catalogo');
Route::resource('catalogo', CatalogoController::class)->only(['index', 'show'])->parameters(['catalogo' => 'product']); Route::resource('catalogo', CatalogoController::class)->only(['index', 'show'])->parameters(['catalogo' => 'product']);
Route::get('login', function(){ return view('login'); })->name('login'); Route::get('login', function(){ return view('login'); })->name('login');
Route::post('login', LoginController::class)->middleware('throttle:5,1')->name('login.attempt'); Route::post('login', LoginController::class)->middleware('throttle:5,1')->name('login.attempt');
Route::view('register', 'register')->name('register'); Route::view('register', 'register')->name('register');
Route::post('register', RegisterController::class)->name('register.store'); Route::post('register', RegisterController::class)->name('register.store');
Route::post('logout', function(){ Route::post('logout', function(){
Auth::guard('web')->logout(); Auth::guard('web')->logout();
Session::invalidate(); Session::invalidate();
Session::regenerateToken(); Session::regenerateToken();
return redirect('/'); return redirect('/');
})->name('logout'); })->name('logout');
// --- RUTAS PROTEGIDAS (Requieren Login) ---
Route::middleware(['auth'])->group(function () { Route::middleware(['auth'])->group(function () {
Route::view('dashboard', 'dashboard')->name('dashboard'); Route::view('dashboard', 'dashboard')->name('dashboard');
Route::resource('clients', ClientController::class); Route::resource('clients', ClientController::class);
Route::resource('productos', ProductosController::class)->parameters([
'productos' => 'product'
]);
Route::resource('sales', SaleController::class)->only(['index', 'create', 'store', 'show']); Route::resource('sales', SaleController::class)->only(['index', 'create', 'store', 'show']);
// Rutas de Taller Route::get('/agenda', [AgendaController::class, 'index'])->name('agenda');
Route::get('/appointments/{appointment}', [AppointmentController::class, 'show'])->name('appointments.show');
// Taller
Route::controller(TallerController::class)->prefix('taller')->name('taller.')->group(function () { Route::controller(TallerController::class)->prefix('taller')->name('taller.')->group(function () {
Route::get('/', 'index')->name('index'); Route::get('/', 'index')->name('index');
Route::get('/create', 'create')->name('create'); Route::get('/create', 'create')->name('create');
Route::post('/', 'store')->name('store'); Route::post('/', 'store')->name('store');
Route::patch('/{appointment}/status', 'updateStatus')->name('updateStatus'); Route::patch('/{appointment}/status', 'updateStatus')->name('updateStatus');
}); });
Route::get('/agenda', [AgendaController::class, 'index'])->name('agenda');
Route::get('/appointments/{appointment}', [AppointmentController::class, 'show']) // Productos: Rutas de lectura para cualquier usuario logueado
->name('appointments.show'); Route::resource('productos', ProductosController::class)
->only(['index', 'show'])
->parameters(['productos' => 'product']);
// --- RUTAS DE ADMINISTRADOR (Solo Admin) ---
Route::middleware(['admin'])->group(function () {
// Solo el admin puede crear, editar o borrar productos
Route::resource('productos', ProductosController::class)
->only(['create', 'store', 'edit', 'update', 'destroy'])
->parameters(['productos' => 'product']);
// Si tienes más cosas de admin (ej: reportes), van aquí
});
}); });