Merge branch 'bryam' of https://github.com/BryamE/ProyectoLauck into giane

This commit is contained in:
gianella
2026-03-13 11:37:52 -03:00
46 changed files with 2310 additions and 368 deletions
+7 -3
View File
@@ -3,6 +3,7 @@
/* 2. Importar Tailwind (v4) */
@import "tailwindcss";
@custom-variant dark (&:is(.dark *));
@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
@source '../../storage/framework/views/*.php';
@source '../**/*.blade.php';
@@ -25,13 +26,16 @@
/* 4. Patrón de fondo estilo "Técnico" */
.bg-grid-pattern {
/* CAMBIO: Usamos rgba(255,255,255, 0.1) para que las líneas sean claras sobre fondo oscuro */
background-image: linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
background-image: linear-gradient(to right, rgba(0, 0, 0, 0.1) 1px, transparent 1px),
linear-gradient(to bottom, rgba(0, 0, 0, 0.1) 1px, transparent 1px);
background-size: 40px 40px;
background-position: center;
}
:is(.dark) .bg-grid-pattern {
background-image: linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
}
/* 5. Personalización del Scrollbar */
::-webkit-scrollbar {
width: 8px;
-54
View File
@@ -1,54 +0,0 @@
<x-layout title="Catalogo - Lauck">
<!-- Header -->
<x-section-header subtitle="Inicio" title="Catalogo de " highlight="Productos"/>
<div class="w-full max-w-5xl">
@if ($products->count() > 0)
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
@foreach ($products as $prod)
<div class="group p-4 border border-neutral-800 rounded-xl hover:border-neon-lime hover:-translate-y-1 transition-all duration-300">
{{-- Imagen si existe --}}
@if (!empty($prod->image_path))
<img src="{{ asset('storage/' . $prod->image_path) }}" alt="{{ $prod->name }}"
class="w-full h-40 object-cover rounded mb-4">
@else
<div class="w-full border border-neutral-800 h-40 bg-stone-900 flex items-center justify-center rounded mb-4">
<span class="text-neon-lime text-md uppercase font-bold">Sin imagen</span>
</div>
@endif
{{-- Nombre --}}
<h2 class="text-lg font-semibold text-white">{{ $prod->name }}</h2>
{{-- Descripción corta --}}
<div class="h-10 overflow-y-auto [scrollbar-width:none]">
@if (!empty($prod->description))
<p class="text-sm text-gray-400 mt-2">{{ $prod->description }}</p>
@endif
</div>
{{-- Precio --}}
@if (!empty($prod->price))
<p class="text-white group-hover:text-neon-lime font-bold mt-3 transition-colors">${{ number_format($prod->price, 2, ',', '.') }}</p>
@endif
{{-- Botón --}}
<a href="{{ route('productos.show', $prod) }}"
class="mt-4 block w-full bg-neon-lime/80 uppercase text-black font-semibold py-2 rounded-lg text-center shadow-md shadow-neon-lime/10 hover:bg-neutral-900/70 border border-transparent hover:text-neon-lime hover:shadow-neon-lime/20 hover:border-neutral-800 transition-all">
Ver +
</a>
</div>
@endforeach
</div>
@else
<p class="text-center text-gray-600 mt-10">No hay productos disponibles.</p>
@endif
<div class="mt-3">
{{ $products->links() }}
</div>
</div>
</x-layout>
+54
View File
@@ -0,0 +1,54 @@
<x-layout title="Catalogo - Lauck">
<!-- Header -->
<x-section-header subtitle="Inicio" title="Catalogo de " highlight="Productos"/>
<div class="w-full max-w-5xl">
@if ($products->count() > 0)
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@foreach ($products as $product)
<div class="group p-4 border bg-stone-200/30 dark:bg-neutral-950/30 border-neutral-200 dark:border-neutral-800 rounded-xl hover:border-lime-500 hover:dark:border-neon-lime hover:-translate-y-1 transition-all duration-300">
{{-- Imagen si existe --}}
@if (!empty($product->image_path))
<img src="{{ asset('storage/' . $product->image_path) }}" alt="{{ $product->name }}"
class="w-full h-40 object-cover rounded mb-4">
@else
<div class="w-full border border-neutral-200 dark:border-neutral-800 h-40 bg-stone-200 dark:bg-stone-900 flex items-center justify-center rounded mb-4">
<span class="text-lime-800 dark:text-neon-lime text-md uppercase font-bold">Sin imagen</span>
</div>
@endif
{{-- Nombre --}}
<h2 class="text-lg font-semibold text-black dark:text-white">{{ $product->name }}</h2>
{{-- Descripción corta --}}
<div class="h-10 overflow-y-auto [scrollbar-width:none]">
@if (!empty($product->description))
<p class="text-sm text-gray-700 dark:text-gray-400 mt-2">{{ $product->description }}</p>
@endif
</div>
{{-- Precio --}}
@if (!empty($product->price))
<p class="text-neutral-900 dark:text-white group-hover:text-lime-700 group-hover:dark:text-neon-lime font-bold mt-3 transition-colors">${{ number_format($product->price, 2, ',', '.') }}</p>
@endif
{{-- Botón --}}
<a href="{{ route('catalogo.show', $product) }}"
class="mt-4 block w-full bg-neutral-900 dark:bg-neon-lime/80 uppercase text-neon-lime dark:text-black font-semibold py-2 rounded-lg text-center shadow-md shadow-gray-900/10 dark:shadow-neon-lime/10 hover:bg-neon-lime hover:dark:bg-neutral-900/70 border border-transparent hover:text-black hover:dark:text-neon-lime hover:border-black hover:dark:border-neon-lime transition-all">
Ver +
</a>
</div>
@endforeach
</div>
@else
<p class="text-center text-gray-400 dark:text-gray-600 mt-10">No hay productos disponibles.</p>
@endif
<div class="mt-3">
{{ $products->links() }}
</div>
</div>
</x-layout>
+111
View File
@@ -0,0 +1,111 @@
<x-layout title="{{ $product->name }} - Lauck">
<div class="container mx-auto px-4 py-8">
<!-- Botón Volver -->
<a href="{{ route('catalogo.index') }}" class="inline-flex items-center text-gray-700 dark:text-gray-400 hover:text-black hover:dark:text-white mb-6 transition-colors">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
Volver al Catálogo
</a>
<div class="bg-slate-100 dark:bg-panel-bg rounded-xl shadow-2xl overflow-hidden border border-neutral-300 dark:border-neutral-800">
<div class="grid grid-cols-1 md:grid-cols-2">
<!-- PANEL IZQUIERDO -->
<div class="bg-zinc-300 dark:bg-neutral-800 relative h-96 md:h-auto min-h-[500px] flex items-center justify-center py-4 group">
@if($product->image_path)
<img src="{{ asset('storage/' . $product->image_path) }}"
alt="{{ $product->name }}"
class="w-full h-full object-contain max-h-[500px] transform drop-shadow-lg">
@else
<div class="text-neutral-400 dark:text-neutral-700 flex flex-col items-center">
<svg class="w-48 h-48" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="0.5" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path></svg>
<span class="mt-4 text-gray-500 text-sm uppercase tracking-widest">Sin Imagen</span>
</div>
@endif
<!-- Badge de Tipo Flotante -->
<div class="absolute top-6 left-6">
<span class="bg-white/50 dark:bg-black/50 backdrop-blur text-black dark:text-white px-3 py-1 rounded-full text-xs font-bold uppercase tracking-wide border border-black/40 dark:border-white/10">
@if($product->type == 'bike')
Bicicleta
@elseif($product->type == 'clothing')
Indumentaria
@elseif($product->type == 'spare')
Repuesto
@else
Accesorio
@endif
</span>
</div>
</div>
<!-- PANEL DERECHO -->
<div class="p-8 md:p-12 flex flex-col justify-center bg-neutral-200 dark:bg-panel-bg">
<!-- Encabezado -->
<div class="mb-6 border-b border-neutral-400 dark:border-neutral-700 pb-6">
<p class="text-stone-500 dark:text-neon-lime text-sm font-bold uppercase tracking-widest mb-2">SKU: {{ $product->sku ?? 'N/A' }}</p>
<h1 class="text-4xl font-black text-black dark:text-white italic mb-2 leading-tight">{{ $product->name }}</h1>
<!-- Stock Status -->
<div class="flex items-center gap-2 mt-4">
@if($product->stock_quantity > 5)
<span class="w-3 h-3 bg-green-600 dark:bg-green-400 rounded-full animate-pulse"></span>
<span class="text-green-700 dark:text-green-400 text-sm font-bold">En Stock ({{ $product->stock_quantity }} unid.)</span>
@elseif($product->stock_quantity > 0)
<span class="w-3 h-3 bg-yellow-600 dark:bg-yellow-400 rounded-full animate-pulse"></span>
<span class="text-yellow-900 dark:text-yellow-400 text-sm font-bold">¡Últimas Unidades! ({{ $product->stock_quantity }})</span>
@else
<span class="w-3 h-3 bg-red-500 rounded-full"></span>
<span class="text-red-700 dark:text-red-400 text-sm font-bold">Agotado</span>
@endif
</div>
</div>
<!-- Precio -->
<div class="mb-8">
<span class="block text-gray-700 dark:text-gray-400 text-xs uppercase mb-1">Precio Contado</span>
<div class="flex items-baseline gap-2">
<span class="text-5xl font-black text-black dark:text-white">${{ number_format($product->price, 0, ',', '.') }}</span>
<span class="text-gray-500 font-medium">ARG</span>
</div>
<p class="text-gray-500 text-xs mt-2">* Consultar financiación en el local.</p>
</div>
<!-- Descripción -->
<div class="mb-8">
<h3 class="text-black dark:text-white font-bold uppercase text-sm mb-3">Descripción</h3>
<p class="text-gray-700 dark:text-gray-400 leading-relaxed">
{{ $product->description ?? 'Sin descripción detallada disponible para este producto. Por favor, acérquese al local para más información.' }}
</p>
</div>
<!-- Botones de Acción -->
<div class="mt-auto grid grid-cols-1 sm:grid-cols-2 gap-4">
<button class="bg-neutral-900 dark:bg-neon-lime text-neon-lime dark:text-neutral-900 font-black py-4 px-6 rounded-lg hover:bg-neutral-800 hover:dark:bg-[#b3e600] transition-all uppercase tracking-wide shadow-lg shadow-black/20 dark:shadow-neon-lime/20 flex items-center justify-center gap-2 transform hover:-translate-y-1">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"></path></svg>
Consultar
</button>
<a href="https://wa.me/3434718739?text=Hola,%20me%20interesa%20el%20producto:%20{{ $product->name }}" target="_blank" class="bg-green-500 dark:bg-neutral-800 text-white font-bold py-4 px-6 rounded-lg hover:bg-green-600 hover:dark:bg-neutral-700 border border-white dark:border-neutral-700 transition-all uppercase tracking-wide flex items-center justify-center gap-2">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.008-.57-.008-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"/></svg>
WhatsApp
</a>
</div>
</div>
</div>
</div>
</div>
</x-layout>
{{-- <a href="{{ route('productos.edit', $product ) }}" class="w-full sm:w-auto px-5 py-2 rounded-full text-white font-semibold bg-blue-600 hover:bg-blue-700">Editar</a>
<form action="{{route('productos.destroy',$product)}}" method="post">
@csrf
@method('DELETE')
<button type="submit" class="w-full sm:w-auto px-5 py-2 rounded-full text-white font-semibold bg-red-600 hover:bg-red-700">
Borrar
</button>
</form> --}}
+4 -1
View File
@@ -1,3 +1,6 @@
{{--
DEPRECADO: Este componente ha sido reemplazado por layout.blade.php para una mejor organización.
@props(['auth' => false])
<!DOCTYPE html>
@@ -120,4 +123,4 @@
});
</script>
</body>
</html>
</html> --}}
+7 -7
View File
@@ -1,16 +1,16 @@
<footer class="bg-neutral-900 border-t border-white/5 mt-auto z-10 w-full">
<footer class="bg-slate-100 dark:bg-neutral-900 border-t border-black/5 dark:border-white/5 mt-auto z-10 w-full">
<div class="w-full max-w-7xl mx-auto p-8">
<div class="sm:flex sm:items-center sm:justify-between">
<a href="{{ url('/') }}" class="flex items-center mb-4 sm:mb-0 space-x-3 rtl:space-x-reverse grayscale opacity-70 hover:grayscale-0 hover:opacity-100 transition-all">
<svg class="h-8 text-neon-lime" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2L2 7l10 5 10-5-10-5zm0 9l2.5-1.25L12 8.5l-2.5 1.25L12 11zm0 2.5l-5-2.5-5 2.5L12 22l10-8.5-5-2.5-5 2.5z"/></svg>
<span class="self-center text-xl font-bold whitespace-nowrap text-white">Cicles Lauck</span>
<svg class="h-8 text-lime-600 dark:text-neon-lime" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2L2 7l10 5 10-5-10-5zm0 9l2.5-1.25L12 8.5l-2.5 1.25L12 11zm0 2.5l-5-2.5-5 2.5L12 22l10-8.5-5-2.5-5 2.5z"/></svg>
<span class="self-center text-xl font-bold whitespace-nowrap dark:text-white">Cicles Lauck</span>
</a>
<ul class="flex flex-wrap items-center mb-6 text-sm font-medium text-gray-500 sm:mb-0">
<li><a href="#" class="hover:text-neon-lime hover:underline me-4 md:me-6 transition-colors">Soporte</a></li>
<li><a href="#" class="hover:text-neon-lime hover:underline transition-colors">Contacto</a></li>
<li><a href="#" class="hover:text-lime-600 hover:dark:text-neon-lime hover:underline me-4 md:me-6 transition-colors">Soporte</a></li>
<li><a href="#" class="hover:text-lime-600 hover:dark:text-neon-lime hover:underline transition-colors">Contacto</a></li>
</ul>
</div>
<hr class="my-6 border-neutral-800 sm:mx-auto lg:my-8">
<span class="block text-sm text-gray-600 sm:text-center">© {{ date('Y') }} <a href="#" class="hover:text-neon-lime transition-colors">Lauck Systems™</a>.</span>
<hr class="my-6 border-neutral-200 dark:border-neutral-800 sm:mx-auto lg:my-8">
<span class="block text-sm text-gray-600 sm:text-center">© {{ date('Y') }} <a href="#" class="hover:text-lime-700 hover:dark:text-neon-lime transition-colors">Lauck Systems™</a>.</span>
</div>
</footer>
@@ -1,6 +1,6 @@
@props(['disabled' => false, 'error' => null])
<input {{ $disabled ? 'disabled' : ''}} {!! $attributes->merge(['class' => 'bg-neutral-800 border-neutral-700 text-white text-sm rounded-lg focus:ring-neon-lime focus:border-neon-lime block w-full p-2.5 placeholder-gray-500 transition-colors ' . ($error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : '')]) !!}>
<input {{ $disabled ? 'disabled' : ''}} {!! $attributes->merge(['class' => 'bg-gray-300 dark:bg-neutral-800 border border-neutral-400 dark:border-neutral-700 dark:text-white text-sm rounded-lg focus:ring-neon-lime focus:border-neon-lime block w-full p-2.5 placeholder-neutral-600 dark:placeholder-gray-400 transition-colors ' . ($error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : '')]) !!}>
@if($error)
<p class="mt-1 text-xs text-red-400">{{ $error }}</p>
@@ -1,5 +1,5 @@
@props(['value'])
<label {!! $attributes->merge(['class' => 'block mb-2 text-xs font-bold text-gray-400 uppercase tracking-wider']) !!}>
<label {!! $attributes->merge(['class' => 'block mb-2 text-xs font-bold text-gray-700 dark:text-gray-300 uppercase tracking-wider']) !!}>
{{$value ?? $slot}}
</label>
+23 -1
View File
@@ -4,13 +4,33 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<script type="module">
// Revisamos el almacenamiento local o las preferencias del sistema
if (localStorage.getItem('theme') === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
// Función global para cambiar el tema desde cualquier botón
window.toggleTheme = function() {
if (document.documentElement.classList.contains('dark')) {
document.documentElement.classList.remove('dark');
localStorage.setItem('theme', 'light');
} else {
document.documentElement.classList.add('dark');
localStorage.setItem('theme', 'dark');
}
}
</script>
<title>{{ $title ?? 'Lauck Dashboard' }}</title>
@stack('styles')
<!-- VITE: Esto carga tu Tailwind compilado y JS -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="bg-dark-bg text-gray-300 font-sans antialiased min-h-screen flex flex-col relative overflow-x-hidden">
<body class="bg-gray-50 dark:bg-dark-bg text-gray-900 dark:text-gray-300 font-sans antialiased min-h-screen flex flex-col relative transition-colors overflow-x-hidden">
<!-- Fondo grilla global -->
<div class="inset-0 bg-grid-pattern opacity-[0.15] z-0 pointer-events-none fixed"></div>
@@ -34,6 +54,8 @@
if(btn && menu) {
btn.addEventListener('click', () => menu.classList.toggle('hidden'));
}
</script>
@stack('scripts')
+26 -19
View File
@@ -1,4 +1,4 @@
<nav class="bg-neutral-900/90 backdrop-blur-md border-b border-white/10 w-full z-50 sticky top-0">
<nav class="bg-slate-100/90 dark:bg-neutral-900/90 backdrop-blur-md border-b border-black/10 dark:border-white/10 w-full z-50 sticky top-0">
<div class="max-w-7xl flex flex-wrap items-center justify-between mx-auto p-4">
<!-- Logo -->
@@ -8,11 +8,11 @@
@guest
<a href="{{ url('/') }}" class="flex items-center space-x-3 rtl:space-x-reverse group">
@endguest
<div class="h-10 w-10 bg-neutral-800 rounded-full flex items-center justify-center border-2 border-transparent group-hover:border-neon-lime transition-all duration-300">
<svg class="w-6 h-6 text-white group-hover:text-neon-lime transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
<div class="h-10 w-10 bg-slate-200 dark:bg-neutral-800 rounded-full flex items-center justify-center border-2 border-transparent group-hover:border-lime-700 group-hover:dark:border-neon-lime transition-all duration-300">
<svg class="w-6 h-6 dark:text-white group-hover:text-lime-700 group-hover:dark:text-neon-lime transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
</div>
<span class="self-center text-2xl font-black whitespace-nowrap text-white italic tracking-wide group-hover:text-neon-lime transition-colors duration-300">
LAUCK<span class="text-neon-lime font-light not-italic">SYS</span>
<span class="self-center text-2xl font-black whitespace-nowrap dark:text-white italic tracking-wide group-hover:text-lime-700 group-hover:dark:text-neon-lime transition-colors duration-300">
LAUCK<span class="text-lime-700 dark:text-neon-lime font-light not-italic">SYS</span>
</span>
</a>
@@ -31,47 +31,54 @@
@auth
<li>
<a href="{{ url('/dashboard') }}"
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('dashboard') ? 'text-neon-lime border-b-2 border-neon-lime' : 'text-white hover:text-neon-lime' }}">
Dashboard
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('dashboard') ? 'text-lime-600 dark:text-neon-lime border-b-2 border-lime-600 dark:border-neon-lime' : 'dark:text-white hover:text-lime-600 hover:dark:text-neon-lime' }}">
Inicio
</a>
</li>
<li>
<a href="{{ url('/productos') }}"
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('productos*') ? 'text-neon-lime border-b-2 border-neon-lime' : 'text-white hover:text-neon-lime' }}">
Stock
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('productos*') ? 'text-lime-600 dark:text-neon-lime border-b-2 border-lime-600 dark:border-neon-lime' : 'dark:text-white hover:text-lime-600 hover:dark:text-neon-lime' }}">
Stock
</a>
</li>
<li>
<a href="#"
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('mantenimiento*') ? 'text-neon-lime border-b-2 border-neon-lime' : 'text-white hover:text-neon-lime' }}">
Taller
<a href="{{ route('taller.index') }}"
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('taller*') ? 'text-lime-600 dark:text-neon-lime border-b-2 border-lime-600 dark:border-neon-lime' : 'dark:text-white hover:text-lime-600 hover:dark:text-neon-lime' }}">
Taller
</a>
</li>
<li>
<a href="{{ route('sales.index') }}"
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('sales*') ? 'text-neon-lime border-b-2 border-neon-lime' : 'text-white hover:text-neon-lime' }}">
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('sales*') ? 'text-lime-600 dark:text-neon-lime border-b-2 border-lime-600 dark:border-neon-lime' : 'dark:text-white hover:text-lime-600 hover:dark:text-neon-lime' }}">
Ventas
</a>
</li>
@endauth
<button onclick="toggleTheme()" class="p-2 text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white transition-colors rounded-full hover:bg-gray-200 dark:hover:bg-neutral-800">
<!-- Icono de Sol (Se muestra en modo oscuro) -->
<svg class="w-5 h-5 hidden dark:block" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>
<!-- Icono de Luna (Se muestra en modo claro) -->
<svg class="w-5 h-5 block dark:hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path></svg>
</button>
{{-- LÓGICA DE VISITANTE (GUEST) --}}
@guest
<li>
<a href="{{ url('/catalogo') }}"
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('catalogo*') ? 'text-neon-lime border-b-2 border-neon-lime' : 'text-white hover:text-neon-lime' }}">
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('catalogo*') ? 'text-lime-600 dark:text-neon-lime border-b-2 border-lime-600 dark:border-neon-lime' : 'dark:text-white hover:text-lime-600 hover:dark:text-neon-lime' }}">
Catalogo
</a>
</li>
<!-- Buscador Integrado -->
<li class="w-full md:w-auto my-2 md:my-0">
<form action="{{ route('catalogo') }}" method="GET">
<form action="{{ route('catalogo.index') }}" method="GET">
<div class="relative">
<input type="text" name="search"
class="block w-full md:w-48 p-2 ps-3 text-xs text-white border border-neutral-600 rounded-full bg-neutral-800/50 focus:ring-neon-lime focus:border-neon-lime placeholder-gray-500 transition-all focus:w-full md:focus:w-64"
class="block w-full md:w-48 p-2 ps-3 text-xs dark:text-white border border-slate-400 dark:border-neutral-600 rounded-full bg-slate-300/50 dark:bg-neutral-800/50 focus:ring-neon-lime focus:border-neon-lime placeholder-gray-500 transition-all focus:w-full md:focus:w-64"
placeholder="Buscar productos...">
<button type="submit" class="absolute top-0 end-0 p-2 text-sm font-medium h-full text-white rounded-e-lg hover:text-neon-lime">
<button type="submit" class="absolute top-0 end-0 p-2 text-sm font-medium h-full dark:text-white rounded-e-lg hover:text-lime-600 hover:dark:text-neon-lime">
<svg class="w-4 h-4" 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>
@@ -83,8 +90,8 @@
<!-- Botón Login Resaltado -->
<li>
<a href="{{ route('login') }}"
class="block py-2 px-5 text-center text-neutral-900 bg-neon-lime font-black rounded hover:bg-[#b3e600] transition-colors uppercase tracking-wider text-xs shadow-lg shadow-neon-lime/20 hover:shadow-neon-lime/40 transform hover:-translate-y-0.5 duration-200">
Ingresar
class="block py-2 px-5 text-center text-neon-lime dark:text-neutral-900 bg-neutral-900 dark:bg-neon-lime font-black rounded hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wider text-xs shadow-lg shadow-gray-300 dark:shadow-neon-lime/20 hover:dark:shadow-neon-lime/40 transform hover:-translate-y-0.5 duration-200">
Ingresar
</a>
</li>
@endguest
@@ -1,11 +1,11 @@
@props(['subtitle', 'title', 'highlight' => null])
<div class="w-full text-left mb-10 border-l-4 border-neon-lime pl-6 py-2">
<h2 class="text-neutral-400 text-sm font-bold uppercase tracking-widest mb-1">{{ $subtitle }}</h2>
<h1 class="font-black text-4xl md:text-5xl text-white uppercase italic">
<div class="w-full text-left mb-10 border-l-4 border-lime-600 dark:border-neon-lime pl-6 py-2">
<h2 class="text-neutral-600 dark:text-neutral-400 text-sm font-bold uppercase tracking-widest mb-1">{{ $subtitle }}</h2>
<h1 class="font-black text-4xl md:text-5xl text-black dark:text-white uppercase italic">
{{ $title }}
@if($highlight)
<span class="text-transparent bg-clip-text bg-gradient-to-r from-white to-gray-500 pe-2">{{ $highlight }}</span>
<span class="text-transparent bg-clip-text bg-gradient-to-r from-neutral-900 dark:from-white to-lime-500 dark:to-gray-500 pe-2">{{ $highlight }}</span>
@endif
</h1>
</div>
@@ -0,0 +1,72 @@
@props(['job', 'color'])
@php
$borderColor = match($color) {
'red' => 'border-l-red-500',
'yellow' => 'border-l-yellow-500',
'neon' => 'border-l-neon-lime',
default => 'border-l-gray-500'
};
@endphp
<div class="bg-panel-bg p-4 rounded-lg border border-neutral-700 border-l-4 {{ $borderColor }} shadow-lg group hover:bg-neutral-800 transition-colors">
<!-- Encabezado Tarjeta -->
<div class="flex justify-between items-start mb-2">
<span class="text-xs font-bold text-gray-400">{{ $job->client->name }}</span>
<span class="text-xs font-mono text-gray-500">{{ $job->scheduled_at->format('d/m H:i') }}</span>
</div>
<h4 class="text-white font-bold text-sm mb-1">{{ $job->bike_model }}</h4>
<p class="text-gray-400 text-xs line-clamp-2 mb-3">{{ $job->problem_description }}</p>
@if($job->estimated_cost)
<div class="text-right mb-3">
<span class="text-xs text-gray-500">Presupuesto:</span>
<span class="text-sm font-mono text-white font-bold">${{ number_format($job->estimated_cost, 0) }}</span>
</div>
@endif
<!-- Controles de Estado -->
<div class="flex justify-between items-center pt-2 border-t border-neutral-700 mt-2 opacity-100 md:opacity-50 group-hover:opacity-100 transition-opacity">
<!-- Botón Mover Atrás -->
@if($job->status !== 'pending')
<form action="{{ route('taller.updateStatus', $job) }}" method="POST">
@csrf @method('PATCH')
<input type="hidden" name="status" value="{{ $job->status === 'ready' ? 'in_progress' : 'pending' }}">
<button class="text-gray-500 hover:text-white p-1" title="Volver al estado anterior">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path></svg>
</button>
</form>
@else
<div></div> <!-- Espaciador -->
@endif
<!-- Enlace a WhatsApp -->
<a href="https://wa.me/{{ $job->contact_phone }}?text=Hola {{ $job->client->name }}, te escribimos de Lauck para avisarte sobre tu {{ $job->bike_model }}..." target="_blank" class="text-green-500 hover:text-green-400">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M17.472 14.382c..."></path></svg> <!-- (Usa el mismo SVG de whatsapp de antes) -->
<span class="text-xs ml-1">Avisar</span>
</a>
<!-- Botón Mover Adelante -->
@if($job->status !== 'ready')
<form action="{{ route('taller.updateStatus', $job) }}" method="POST">
@csrf @method('PATCH')
<input type="hidden" name="status" value="{{ $job->status === 'pending' ? 'in_progress' : 'ready' }}">
<button class="text-neon-lime hover:text-white p-1" title="Avanzar estado">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
</button>
</form>
@elseif($job->status === 'ready')
<!-- Botón Entregar (Archivar) -->
<form action="{{ route('taller.updateStatus', $job) }}" method="POST">
@csrf @method('PATCH')
<input type="hidden" name="status" value="delivered">
<button class="text-xs bg-neon-lime text-black px-2 py-1 rounded font-bold hover:bg-white" title="Marcar como entregado">
Entregar
</button>
</form>
@endif
</div>
</div>
@@ -1,11 +1,11 @@
@if (session('success'))
<div class="p-4 mb-4 text-sm text-green-400 rounded-lg bg-neutral-800 border border-green-800/50" role="alert">
<div class="p-4 mb-4 text-md text-black rounded-lg bg-green-500 border border-green-800/50" role="alert">
<span class="font-bold">¡Éxito!</span> {{ session('success') }}
</div>
@endif
@if (session('error'))
<div class="p-4 mb-4 text-sm text-red-400 rounded-lg bg-neutral-800 border border-red-800/50" role="alert">
<div class="p-4 mb-4 text-md text-black rounded-lg bg-red-500 border border-red-800/50" role="alert">
<span class="font-bold">Error:</span> {{ session('error') }}
</div>
@endif
@@ -2,11 +2,12 @@
@php
$colors = [
'gray' => 'bg-gray-700 text-gray-300',
'red' => 'bg-red-900/50 text-red-300 border border-red-800',
'green' => 'bg-green-900/50 text-green-300 border border-green-800',
'yellow' => 'bg-yellow-900/50 text-yellow-300 border border-yellow-800',
'neon' => 'bg-[#ccff00]/10 text-[#ccff00] border border-[#ccff00]/50',
'gray' => 'bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-300',
'red' => 'bg-red-200 dark:bg-red-900/50 text-red-800 dark:text-red-300 border border-red-500 dark:border-red-800',
'blue' => 'bg-blue-200 dark:bg-blue-900/50 text-blue-800 dark:text-blue-300 border border-blue-500 dark:border-blue-800',
'green' => 'bg-green-200 dark:bg-green-900/50 text-green-800 dark:text-green-300 border border-green-500 dark:border-green-800',
'yellow' => 'bg-yellow-200 dark:bg-yellow-900/50 text-yellow-800 dark:text-yellow-300 border border-yellow-500 dark:border-yellow-800',
'neon' => 'bg-lime-200 dark:bg-[#ccff00]/10 text-lime-800 dark:text-[#ccff00] border border-lime-700 dark:border-[#ccff00]/50',
];
$classes = $colors[$color] ?? $colors['gray'];
@endphp
+5 -5
View File
@@ -1,15 +1,15 @@
@props(['href' => '#', 'title', 'description', 'linkText' => 'Ver detalles'])
<a href="{{ $href }}" class="group relative block p-6 bg-panel-bg border border-neutral-800 rounded-xl hover:border-neon-lime hover:-translate-y-1 transition-all duration-300 shadow-lg hover:shadow-neon-lime/20 h-full">
<a href="{{ $href }}" class="group relative block p-6 bg-white dark:bg-panel-bg border border-neutral-200 dark:border-neutral-800 rounded-xl hover:border-neutral-600 hover:dark:border-neon-lime hover:-translate-y-1 transition-all duration-300 shadow-lg hover:dark:shadow-neon-lime/20 h-full">
<!-- slot para SVG -->
<div class="absolute top-0 right-0 p-4 opacity-10 group-hover:opacity-100 transition-opacity">
<div class="absolute top-0 right-0 p-4 opacity-30 dark:opacity-10 group-hover:opacity-100 transition-opacity">
{{ $slot }}
</div>
<h3 class="mt-4 text-xl font-bold text-white group-hover:text-neon-lime transition-colors">{{ $title }}</h3>
<p class="mt-2 text-sm text-gray-500">{{ $description }}</p>
<h3 class="mt-4 text-xl font-bold text-black dark:text-white group-hover:text-lime-500 group-hover:dark:text-neon-lime transition-colors">{{ $title }}</h3>
<p class="mt-2 text-sm text-gray-700 dark:text-gray-500">{{ $description }}</p>
<div class="mt-6 inline-flex items-center text-xs font-bold text-neon-lime uppercase tracking-wider">
<div class="mt-6 inline-flex items-center text-xs font-bold text-lime-500 dark:text-neon-lime uppercase tracking-wider">
{{ $linkText }} <span class="ml-2 group-hover:translate-x-1 transition-transform"></span>
</div>
</a>
@@ -1,10 +1,10 @@
@props(['items'])
<div class="relative w-full overflow-hidden rounded-xl border border-neutral-800 bg-panel-bg shadow-xl group" id="lauck-carousel">
<div class="relative w-full overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-800 bg-slate-50 dark:bg-panel-bg shadow-xl group" id="lauck-carousel">
<!-- Título Flotante (Opcional) -->
<div class="absolute top-4 left-6 z-10 bg-black/50 backdrop-blur-sm px-3 py-1 rounded border border-neon-lime/30">
<span class="text-xs font-bold text-neon-lime uppercase tracking-widest">Destacados</span>
<div class="absolute top-4 left-6 z-10 bg-neon-lime/50 dark:bg-black/50 backdrop-blur-sm px-3 py-1 rounded border border-black/30 dark:border-neon-lime/30">
<span class="text-xs font-bold text-black dark:text-neon-lime uppercase tracking-widest">Destacados</span>
</div>
<!-- Contenedor de Slides (Track) -->
@@ -13,40 +13,40 @@
<div class="w-full flex-shrink-0 flex flex-col md:flex-row h-full relative">
<!-- Imagen / Visual (Izquierda o Fondo) -->
<div class="w-full md:w-1/2 bg-neutral-800 flex items-center justify-center relative overflow-hidden">
<div class="w-full md:w-1/2 bg-neutral-200 dark:bg-neutral-800 flex items-center justify-center relative overflow-hidden">
<!-- Decoración de fondo -->
<div class="absolute inset-0 bg-grid-pattern opacity-10"></div>
<!-- Icono Gigante (Placeholder de Bici) -->
<div class="text-neutral-700 transform group-hover:scale-110 transition-transform duration-700">
<div class="text-neutral-300 dark:text-neutral-700 transform group-hover:scale-110 transition-transform duration-700">
@if($item->image_path)
<img src="{{ asset('storage/' . $item->image_path) }}" alt="{{ $item->name }}" class="w-full h-full object-cover">
@else
<!-- Placeholder si no tiene foto -->
<div class="w-full h-full flex items-center justify-center bg-neutral-800">
<div class="w-full h-full flex items-center justify-center bg-neutral-200 dark:bg-neutral-800">
<svg class="w-48 h-48" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="0.5" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path></svg>
</div>
@endif
</div>
<!-- Precio Flotante -->
<div class="absolute bottom-4 left-4 bg-neon-lime text-neutral-900 font-black px-4 py-2 rounded-lg text-xl shadow-lg shadow-neon-lime/20">
<div class="absolute bottom-4 left-4 bg-neutral-900 dark:bg-neon-lime text-neon-lime dark:text-neutral-900 font-black px-4 py-2 rounded-lg text-xl shadow-lg shadow-gray-800/10 dark:shadow-neon-lime/20">
${{ number_format($item->price, 0, ',', '.') }}
</div>
</div>
<!-- Info (Derecha) -->
<div class="w-full md:w-1/2 p-8 md:p-12 flex flex-col justify-center bg-gradient-to-br from-panel-bg to-neutral-900">
<h3 class="text-sm font-bold text-gray-400 uppercase tracking-widest mb-2">{{ $item->sku }}</h3>
<h2 class="text-3xl md:text-4xl font-black text-white italic mb-4 leading-tight">
<div class="w-full md:w-1/2 p-8 md:p-12 flex flex-col justify-center bg-gradient-to-br from-gray-200 dark:from-panel-bg to-neutral-100 dark:to-neutral-900">
<h3 class="text-sm font-bold text-gray-600 dark:text-gray-400 uppercase tracking-widest mb-2">{{ $item->sku }}</h3>
<h2 class="text-3xl md:text-4xl font-black text-black dark:text-white italic mb-4 leading-tight">
{{ $item->name }}
</h2>
<p class="text-gray-400 text-sm md:text-base mb-8 line-clamp-3">
<p class="text-gray-600 dark:text-gray-400 text-sm md:text-base mb-8 line-clamp-3">
{{ $item->description ?? 'Una bicicleta diseñada para el máximo rendimiento en todo terreno. Consultar especificaciones técnicas en el catálogo.' }}
</p>
<div class="flex gap-4">
<a href="{{ route('catalogo', ['search' => $item->sku]) }}" class="px-6 py-3 bg-white text-neutral-900 font-bold uppercase tracking-wider rounded hover:bg-gray-200 transition-colors">
<a href="{{ route('catalogo.show', $item) }}" class="px-6 py-3 bg-black dark:bg-white text-neutral-100 dark:text-neutral-900 font-bold uppercase tracking-wider rounded hover:bg-neutral-800 hover:dark:bg-gray-200 transition-colors">
Ver Detalles
</a>
</div>
@@ -54,7 +54,7 @@
</div>
@empty
<!-- Slide de Fallback por si no hay datos -->
<div class="w-full flex-shrink-0 flex items-center justify-center h-full bg-neutral-800 text-gray-500">
<div class="w-full flex-shrink-0 flex items-center justify-center h-full bg-neutral-200 dark:bg-neutral-800 text-gray-500">
<p>No hay productos destacados disponibles.</p>
</div>
@endforelse
@@ -72,7 +72,7 @@
<!-- Indicadores (Puntos) -->
<div class="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex space-x-2 z-20">
@foreach($items as $index => $item)
<button class="carousel-dot w-3 h-3 rounded-full bg-white/20 hover:bg-neon-lime transition-all" data-index="{{ $index }}"></button>
<button class="carousel-dot w-3 h-3 rounded-full bg-black/20 dark:bg-white/20 hover:bg-lime-500 hover:dark:bg-neon-lime transition-all" data-index="{{ $index }}"></button>
@endforeach
</div>
@@ -91,8 +91,8 @@
$track.css('transform', `translateX(${translateX}%)`);
// Actualizar puntos
$('.carousel-dot').removeClass('bg-neon-lime scale-125').addClass('bg-white/20');
$(`.carousel-dot[data-index="${currentIndex}"]`).addClass('bg-neon-lime scale-125').removeClass('bg-white/20');
$('.carousel-dot').removeClass('bg-lime-500 dark:bg-neon-lime scale-125').addClass('bg-black/20 dark:bg-white/20');
$(`.carousel-dot[data-index="${currentIndex}"]`).addClass('bg-lime-500 dark:bg-neon-lime scale-125').removeClass('bg-black/20 dark:bg-white/20');
}
function nextSlide() {
+37 -18
View File
@@ -9,30 +9,49 @@
<!-- Grid de Tarjetas -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 w-full mb-12">
<!-- Tarjeta Catálogo -->
<x-ui.card href="{{ url('/catalogo') }}" title="Catálogo" description="Administrar bicicletas y repuestos." linkText="Ir al stock">
<svg class="w-12 h-12 text-neon-lime" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" /></svg>
</x-ui.card>
<!-- Tarjeta Taller -->
<x-ui.card href="#" title="Taller" description="Gestión de services y reparaciones." linkText="Ver agenda">
<svg class="w-12 h-12 text-neon-lime" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
<x-ui.card href="{{ url('/catalogo') }}" title="Catálogo" description="Ver productos." linkText="Ir al catalogo">
<svg class="w-12 h-12 text-lime-500 dark:text-neon-lime" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" /></svg>
</x-ui.card>
<!-- Tarjeta Clientes -->
<x-ui.card href="{{ url('/clients') }}" title="Clientes" description="Base de datos de ciclistas." linkText="Buscar usuario">
<svg class="w-12 h-12 text-neon-lime" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" /></svg>
<x-ui.card href="{{ url('/clients') }}" title="Clientes" description="Base de datos de ciclistas." linkText="Ver Clientes">
<svg class="w-12 h-12 text-lime-500 dark:text-neon-lime" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" /></svg>
</x-ui.card>
<!-- Tarjeta Ventas -->
<x-ui.card href="{{ url('/sales') }}" title="Ventas" description="Registro de Ventas" linkText="Ver Ventas">
<svg class="w-14 h-14 text-lime-500 dark:text-neon-lime" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M13.6 16.733c.234.269.548.456.895.534a1.4 1.4 0 0 0 1.75-.762c.172-.615-.446-1.287-1.242-1.481-.796-.194-1.41-.861-1.241-1.481a1.4 1.4 0 0 1 1.75-.762c.343.077.654.26.888.524m-1.358 4.017v.617m0-5.939v.725M4 15v4m3-6v6M6 8.5 10.5 5 14 7.5 18 4m0 0h-3.5M18 4v3m2 8a5 5 0 1 1-10 0 5 5 0 0 1 10 0Z"></path>
</svg>
</x-ui.card>
<!-- Tarjeta Taller -->
<x-ui.card href="{{ url('/taller') }}" title="Taller" description="Gestión de services y reparaciones." linkText="Ver agenda">
<svg class="w-12 h-12 text-lime-500 dark:text-neon-lime" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linejoin="round" stroke-width="1.5" d="M7.58209 8.96025 9.8136 11.1917l-1.61782 1.6178c-1.08305-.1811-2.23623.1454-3.07364.9828-1.1208 1.1208-1.32697 2.8069-.62368 4.1363.14842.2806.42122.474.73509.5213.06726.0101.1347.0133.20136.0098-.00351.0666-.00036.1341.00977.2013.04724.3139.24069.5867.52125.7351 1.32944.7033 3.01552.4971 4.13627-.6237.8375-.8374 1.1639-1.9906.9829-3.0736l4.8107-4.8108c1.0831.1811 2.2363-.1454 3.0737-.9828 1.1208-1.1208 1.3269-2.80688.6237-4.13632-.1485-.28056-.4213-.474-.7351-.52125-.0673-.01012-.1347-.01327-.2014-.00977.0035-.06666.0004-.13409-.0098-.20136-.0472-.31386-.2406-.58666-.5212-.73508-1.3294-.70329-3.0155-.49713-4.1363.62367-.8374.83741-1.1639 1.9906-.9828 3.07365l-1.7788 1.77875-2.23152-2.23148-1.41419 1.41424Zm1.31056-3.1394c-.04235-.32684-.24303-.61183-.53647-.76186l-1.98183-1.0133c-.38619-.19746-.85564-.12345-1.16234.18326l-.86321.8632c-.3067.3067-.38072.77616-.18326 1.16235l1.0133 1.98182c.15004.29345.43503.49412.76187.53647l1.1127.14418c.3076.03985.61628-.06528.8356-.28461l.86321-.8632c.21932-.21932.32446-.52801.2846-.83561l-.14417-1.1127ZM19.4448 16.4052l-3.1186-3.1187c-.7811-.781-2.0474-.781-2.8285 0l-.1719.172c-.7811.781-.7811 2.0474 0 2.8284l3.1186 3.1187c.7811.781 2.0474.781 2.8285 0l.1719-.172c.7811-.781.7811-2.0474 0-2.8284Z"/>
</svg>
</x-ui.card>
<!-- Tarjeta Productos -->
<x-ui.card href="{{ url('/productos') }}" title="Stock" description="Administrar bicicletas y repuestos." linkText="Ir al stock">
<svg class="w-12 h-12 text-lime-500 dark:text-neon-lime" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" /></svg>
</x-ui.card>
<!-- Tarjeta Proveedores -->
<x-ui.card href="#" title="Proveedores" description="Base de datos de proveedores." linkText="Ver Proveedores">
<svg class="w-12 h-12 text-lime-500 dark:text-neon-lime" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
</x-ui.card>
<!-- Tarjeta Compras -->
<x-ui.card href="#" title="Gastos" description="Registro de compras y pedidos a proovedores." linkText="Ver Gastos">
<svg class="w-12 h-12 text-lime-500 dark:text-neon-lime" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15 4h3a1 1 0 0 1 1 1v15a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h3m0 3h6m-3 5h3m-6 0h.01M12 16h3m-6 0h.01M10 3v4h4V3h-4Z"/>
</svg>
</x-ui.card>
<!-- Estadísticas (Sin template) -->
<div class="p-6 bg-gradient-to-br from-neutral-800 to-neutral-900 border border-neutral-700 rounded-xl flex flex-col justify-center items-center text-center">
<span class="text-4xl font-black text-white">85%</span>
<span class="text-xs uppercase tracking-widest text-gray-500 mt-1">Eficiencia Taller</span>
<div class="w-full bg-gray-700 rounded-full h-1.5 mt-4">
<div class="bg-neon-lime h-1.5 rounded-full" style="width: 85%"></div>
</div>
</div>
</div>
<!-- Botón de Logout -->
+1 -1
View File
@@ -11,7 +11,7 @@
/>
-->
<div class="bg-zinc-900 p-8 rounded-xl shadow-lg w-full max-w-md border-2 border-gray-500">
<div class="bg-panel-bg p-8 rounded-xl shadow-lg w-full max-w-md border border-neutral-700">
<form action="{{ route('login.attempt') }}" method="POST" class="space-y-5">
@csrf
{{-- No muestra los errores, ver --}}
+11 -10
View File
@@ -2,7 +2,7 @@
<x-section-header subtitle="Inventario" title="Nuevo " highlight="Producto" />
<div class="w-full max-w-4xl mx-auto bg-panel-bg border border-neutral-800 rounded-xl p-8 shadow-lg">
<div class="w-full max-w-4xl mx-auto bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-8 shadow-lg">
<form action="{{ route('productos.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@@ -25,10 +25,11 @@
<!-- Tipo -->
<div class="md:col-span-2">
<x-forms.label for="type" value="Tipo de Producto" />
<select id="type" name="type" class="bg-neutral-800 border-neutral-700 text-white text-sm rounded-lg focus:ring-neon-lime focus:border-neon-lime block w-full p-2.5">
<option value="accessory" {{ old('type') == 'accessory' ? 'selected' : '' }}>Accesorio / Repuesto</option>
<select id="type" name="type" class="bg-gray-300 dark:bg-neutral-800 border border-neutral-400 dark:border-neutral-700 dark:text-white text-sm rounded-lg focus:ring-neon-lime focus:border-neon-lime block w-full p-2.5">
<option value="accessory" {{ old('type') == 'accessory' ? 'selected' : '' }}>Accesorio</option>
<option value="bike" {{ old('type') == 'bike' ? 'selected' : '' }}>Bicicleta</option>
<option value="service" {{ old('type') == 'service' ? 'selected' : '' }}>Servicio / Mano de Obra</option>
<option value="clothing" {{ old('type') == 'clothing' ? 'selected' : '' }}>Indumentaria</option>
<option value="spare" {{ old('type') == 'spare' ? 'selected' : '' }}>Repuesto</option>
</select>
</div>
@@ -57,22 +58,22 @@
<!-- Descripción (2 columnas) -->
<div class="md:col-span-4">
<x-forms.label for="description" value="Descripción / Notas" />
<textarea id="description" name="description" rows="3" class="bg-neutral-800 border-neutral-700 text-white text-sm rounded-lg focus:ring-neon-lime focus:border-neon-lime block w-full p-2.5 placeholder-gray-500">{{ old('description') }}</textarea>
<textarea id="description" name="description" rows="3" class="bg-gray-300 dark:bg-neutral-800 border border-neutral-400 dark:border-neutral-700 dark:text-white text-sm rounded-lg focus:ring-neon-lime focus:border-neon-lime block w-full p-2.5 placeholder-neutral-600 dark:placeholder-gray-400">{{ old('description') }}</textarea>
</div>
<div class="md:col-span-2">
<x-forms.label for="image" value="Imagen del Producto" />
<x-forms.input type="file" name="image" class="block w-full text-sm text-gray-400 file:mr-4 file:py-2 file:px-4 file:rounded-full
file:border-0 file:text-sm file:font-semibold file:bg-neon-lime file:text-neutral-900 hover:file:bg-[#b3e600]
<x-forms.input type="file" name="image" class="block w-full text-sm dark:text-gray-400 file:mr-4 file:py-2 file:px-4 file:rounded-full
file:border-0 file:text-sm file:font-semibold file:bg-lime-500 dark:file:bg-neon-lime file:text-neutral-900 hover:file:bg-[#b3e600]
" :error="$errors->first('image')"/>
{{-- @error('image') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror --}}
</div>
</div>
<!-- Botones Acción -->
<div class="flex items-center justify-between md:justify-end space-x-4 border-t border-neutral-800 pt-6">
<a href="{{ route('productos.index') }}" class="text-gray-400 hover:text-white font-medium text-sm transition-colors">Cancelar</a>
<button type="submit" class="px-6 py-2.5 bg-neon-lime text-neutral-900 font-bold rounded-lg hover:bg-[#b3e600] transition-colors shadow-lg shadow-neon-lime/20">
<div class="flex items-center justify-between md:justify-end space-x-4 border-t border-neutral-400 dark:border-neutral-700 pt-6">
<a href="{{ route('productos.index') }}" class="text-gray-700 dark:text-gray-400 hover:text-black hover:dark:text-white font-medium text-sm transition-colors">Cancelar</a>
<button type="submit" class="px-6 py-2.5 bg-neutral-900 dark:bg-neon-lime text-neon-lime dark:text-neutral-900 font-bold rounded-lg hover:bg-neutral-800 hover:dark:bg-[#b3e600] transition-colors shadow-lg dark:shadow-neon-lime/20">
Guardar
</button>
</div>
+3 -58
View File
@@ -1,59 +1,3 @@
{{-- <x-appc>
<x-slot name="title">Lauck - Editar</x-slot>
<x-slot name="navTitle">Editar - {{$product->nombre}}</x-slot>
<div class="w-full h-fit flex flex-col justify-start items-center gap-3 p-18">
<form class="w-lg mx-auto" action="{{route('productos.update',$product)}}" method="POST">
@csrf
@method('PUT')
<div class="relative z-0 w-full mb-5 group">
<input type="text" value="{{$product->nombre}}" name="nombre" id="nombre" class="block py-2.5 px-0 w-full text-sm text-gray-300 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer"/>
<label for="nombre" class="peer-focus:font-medium absolute text-sm text-gray-300 dark:text-gray-300 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 rtl:peer-focus:translate-x-1/4 rtl:peer-focus:left-auto peer-focus:text-blue-600 peer-focus:dark:text-blue-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">Titulo</label>
</div>
<div class="relative z-0 w-full mb-5 group">
<input type="text" value="{{$product->marca}}" name="marca" id="marca" class="block py-2.5 px-0 w-full text-sm text-gray-300 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer"/>
<label for="marca" class="peer-focus:font-medium absolute text-sm text-gray-300 dark:text-gray-300 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 rtl:peer-focus:translate-x-1/4 peer-focus:text-blue-600 peer-focus:dark:text-blue-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">Marca</label>
</div>
<div class="relative z-0 w-full mb-5 group">
<input type="text" value="{{$product->modelo}}" name="modelo" id="modelo" class="block py-2.5 px-0 w-full text-sm text-gray-300 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer"/>
<label for="modelo" class="peer-focus:font-medium absolute text-sm text-gray-300 dark:text-gray-300 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 rtl:peer-focus:translate-x-1/4 peer-focus:text-blue-600 peer-focus:dark:text-blue-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">Modelo</label>
</div>
<div class="relative z-0 w-full mb-5 group">
<textarea type="text" name="descripcion" id="descripcion" class="block py-2.5 px-0 w-full text-sm text-gray-300 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer">{{$product->descripcion}}</textarea>
<label for="descripcion" class="peer-focus:font-medium absolute text-sm text-gray-300 dark:text-gray-300 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 rtl:peer-focus:translate-x-1/4 peer-focus:text-blue-600 peer-focus:dark:text-blue-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">Descripcion</label>
</div>
<div class="grid md:grid-cols-2 md:gap-6">
<div class="relative z-0 w-full mb-5 group">
<input type="number" value="{{$product->rodado}}" name="rodado" id="rodado" class="block py-2.5 px-0 w-full text-sm text-gray-300 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer"/>
<label for="rodado" class="peer-focus:font-medium absolute text-sm text-gray-300 dark:text-gray-300 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 rtl:peer-focus:translate-x-1/4 peer-focus:text-blue-600 peer-focus:dark:text-blue-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">Rodado</label>
</div>
<div class="relative z-0 w-full mb-5 group">
<input type="text" value="{{$product->color}}" name="color" id="color"class="block py-2.5 px-0 w-full text-sm text-gray-300 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer"/>
<label for="color" class="peer-focus:font-medium absolute text-sm text-gray-300 dark:text-gray-300 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 rtl:peer-focus:translate-x-1/4 peer-focus:text-blue-600 peer-focus:dark:text-blue-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">Color</label>
</div>
</div>
<div class="grid md:grid-cols-2 md:gap-6">
<div class="relative z-0 w-full mb-5 group">
<input type="text" value="{{$product->tipo}}" name="tipo" id="tipo" class="block py-2.5 px-0 w-full text-sm text-gray-300 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer"/>
<label for="tipo" class="peer-focus:font-medium absolute text-sm text-gray-300 dark:text-gray-300 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 rtl:peer-focus:translate-x-1/4 peer-focus:text-blue-600 peer-focus:dark:text-blue-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">Tipo</label>
</div>
<div class="relative z-0 w-full mb-5 group">
<input type="number" value={{$product->precio}} name="precio" id="precio" class="block py-2.5 px-0 w-full text-sm text-gray-300 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer" step="0.01"/>
<label for="precio" class="peer-focus:font-medium absolute text-sm text-gray-300 dark:text-gray-300 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 rtl:peer-focus:translate-x-1/4 peer-focus:text-blue-600 peer-focus:dark:text-blue-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">Precio (Ej. $9999)</label>
</div>
</div>
<div class="flex w-full gap-5">
<button type="submit" class="w-full sm:w-auto px-4 py-2 rounded-full text-white font-semibold bg-blue-700 hover:bg-blue-800 dark:bg-blue-700 dark:hover:bg-blue-800">
Editar
</button>
<a href="{{route('productos.show',$product)}}" class="w-full sm:w-auto px-5 py-2 rounded-full text-white font-semibold bg-stone-500">
Volver
</a>
</div>
</form>
</div>
</x-appc> --}}
<x-layout title="Lauck - Editar Producto">
<x-section-header subtitle="Inventario" title="Edicion de " highlight="Producto" />
@@ -76,9 +20,10 @@
<div class="md:col-span-2">
<x-forms.label for="type" value="Tipo de Producto" />
<select id="type" name="type" class="bg-neutral-800 border-neutral-700 text-white text-sm rounded-lg focus:ring-neon-lime focus:border-neon-lime block w-full p-2.5">
<option value="accessory" {{ $product->type == 'accessory' ? 'selected' : '' }}>Accesorio / Repuesto</option>
<option value="accessory" {{ $product->type == 'accessory' ? 'selected' : '' }}>Accesorio</option>
<option value="bike" {{ $product->type == 'bike' ? 'selected' : '' }}>Bicicleta</option>
<option value="service" {{ $product->type == 'service' ? 'selected' : '' }}>Servicio / Mano de Obra</option>
<option value="clothing" {{ $product->type == 'clothing' ? 'selected' : '' }}>Indumentaria</option>
<option value="spare" {{ $product->type == 'spare' ? 'selected' : '' }}>Repuesto</option>
</select>
</div>
<!-- Precios -->
+20 -21
View File
@@ -12,36 +12,36 @@
<form action="{{ route('productos.index') }}" method="GET" class="w-full lg:w-2/3 flex flex-col sm:flex-row gap-3">
<div class="relative w-full sm:w-2/3">
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">
<svg class="w-4 h-4 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" 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-white border border-neutral-700 rounded-lg bg-neutral-800 focus:ring-neon-lime focus:border-neon-lime placeholder-gray-500"
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"
placeholder="Buscar por nombre, SKU o marca...">
</div>
<!-- Filtro de Estado de Stock -->
<div class="w-full sm:w-1/3">
<select name="stock_status" onchange="this.form.submit()"
class="block w-full p-3 text-sm text-white border border-neutral-700 rounded-lg 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="">Todos</option>
<option value="low" {{ request('stock_status') == 'low' ? 'selected' : '' }} class="text-red-300">Stock en Alerta</option>
<option value="medium" {{ request('stock_status') == 'medium' ? 'selected' : '' }} class="text-yellow-300">Stock Bajo</option>
<option value="ok" {{ request('stock_status') == 'ok' ? 'selected' : '' }} class="text-green-300">Stock Normal</option>
<option value="low" {{ request('stock_status') == 'low' ? 'selected' : '' }} class="text-red-600 dark:text-red-300">Stock en Alerta</option>
<option value="medium" {{ request('stock_status') == 'medium' ? 'selected' : '' }} class="text-yellow-600 dark:text-yellow-300">Stock Bajo</option>
<option value="ok" {{ request('stock_status') == 'ok' ? 'selected' : '' }} class="text-green-600 dark:text-green-300">Stock Normal</option>
</select>
</div>
</form>
<!-- Botón Nuevo -->
<a href="{{ route('productos.create') }}" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-neutral-900 bg-neon-lime rounded-lg hover:bg-[#b3e600] transition-colors uppercase tracking-wide">
<a href="{{ route('productos.create') }}" class="w-full md: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 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
+ Nuevo Producto
</a>
</div>
<!-- Tabla de Productos -->
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-neutral-800 w-full">
<table class="w-full text-sm text-left rtl:text-right text-gray-400">
<thead class="text-xs text-gray-300 uppercase bg-neutral-800 border-b border-neutral-700">
<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">
<tr>
<th scope="col" class="px-6 py-3">Producto / SKU</th>
<th scope="col" class="px-6 py-3">Tipo</th>
@@ -52,32 +52,31 @@
</thead>
<tbody>
@forelse($products as $product)
<tr class="bg-neutral-900/50 border-b border-neutral-800 hover:bg-neutral-800 transition-colors group">
<td class="px-6 py-4 font-medium text-white whitespace-nowrap">
<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-500 font-mono">{{ $product->sku }}</div>
<div class="text-xs text-gray-600 dark:text-gray-400 font-mono">{{ $product->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 === 'accessory') <x-ui.badge color="gray">Accesorio</x-ui.badge>
@else <x-ui.badge color="yellow">Servicio</x-ui.badge> @endif
@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>
@else <x-ui.badge color="yellow">Accesorio</x-ui.badge> @endif
</td>
<td class="px-6 py-4 font-mono text-white">
<td class="px-6 py-4 font-mono">
${{ number_format($product->price, 2) }}
</td>
<td class="px-6 py-4 text-center">
@if($product->type === 'service')
<span class="text-gray-600">-</span>
@elseif($product->stock_quantity < $product->min_stock_alert)
@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+1)
@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">
<a href="{{ route('productos.edit', $product) }}" class="font-medium text-blue-400 hover:underline mr-3">Editar</a>
<a href="{{ route('productos.edit', $product) }}" class="font-semibold dark:font-medium text-blue-800 dark:text-blue-400 hover:underline mr-3">Editar</a>
</td>
</tr>
@empty
@@ -1,9 +1,9 @@
<x-appc>
<div class="max-w-6xl mx-auto px-4 py-8 text-white">
<a href="{{ route('catalogo') }}">Volver a catalogo</a>
<h1>Titulo: {{ $producto->nombre }}</h1>
<h1>Titulo: {{ $producto->name }}</h1>
<p>
<b>Categoria:</b> {{ $producto->Categoria }}
<b>Categoria:</b> {{ $producto->type }}
</p>
<p>
{{ $producto->content }}
+20 -29
View File
@@ -36,32 +36,23 @@
<x-section-header subtitle="Punto de Venta" title="Nueva " highlight="Venta" />
<x-ui.alert />
@if($errors->any())
<div class="bg-red-900/50 border border-red-500 text-red-300 px-4 py-3 rounded-lg mb-6 shadow-sm">
<ul class="list-disc list-inside">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="w-full max-w-5xl mx-auto bg-panel-bg border border-neutral-800 rounded-xl p-8 shadow-lg">
@if(session('success'))
<div class="bg-green-900/50 border border-green-500 text-green-300 px-4 py-3 rounded-lg mb-6 shadow-sm">
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="bg-red-900/50 border border-red-500 text-red-300 px-4 py-3 rounded-lg mb-6 shadow-sm">
{{ session('error') }}
</div>
@endif
@if($errors->any())
<div class="bg-red-900/50 border border-red-500 text-red-300 px-4 py-3 rounded-lg mb-6 shadow-sm">
<ul class="list-disc list-inside">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('sales.store') }}" method="POST">
@csrf
<div class="grid grid-cols-1 md:grid-cols-12 gap-6 mb-8 border-b border-neutral-800 pb-8">
<div class="grid grid-cols-1 md:grid-cols-12 gap-6 mb-4 border-b border-neutral-700 pb-8">
<div class="md:col-span-10">
<x-forms.label for="client_id" value="Cliente" />
<div class="relative">
@@ -73,14 +64,14 @@
</select>
</div>
</div>
<div class="md:col-span-2 flex items-end">
<a href="{{ route('clients.create', ['origin' => 'sales']) }}" target="_blank" class="bg-indigo-100 text-indigo-700 hover:bg-indigo-200 px-4 py-2 rounded-md font-bold flex items-center border border-indigo-200" title="Crear nuevo cliente">
+
</a>
<div class="md:col-span-2 flex items-end mb-1">
<a href="{{ route('clients.create', ['origin' => 'sales']) }}" target="_blank"
class="inline-flex items-center text-neon-lime hover:text-[#b3e600] font-bold text-sm transition-colors"
title="Crear nuevo cliente">+ Nuevo Cliente</a>
</div>
</div>
<div class="mb-8">
<div class="mb-4">
<div class="flex justify-between items-end mb-4">
<x-forms.label value="Detalle de Productos" />
<div class="text-sm text-gray-400">
@@ -107,7 +98,7 @@
<div class="md:col-span-2">
<label class="block text-gray-400 text-xs mb-1.5 uppercase tracking-wider font-semibold">Cant.</label>
<input type="number" name="items[0][quantity]" value="1" min="1"
class="quantity-input bg-neutral-800 border-neutral-700 text-white text-sm rounded-lg focus:ring-neon-lime focus:border-neon-lime block w-full p-2.5 h-[42px]">
class="quantity-input bg-neutral-800 border-neutral-700 border rounded-lg text-white text-sm focus:ring-neon-lime focus:border-neon-lime block w-full p-1 px-2 h-7">
</div>
<div class="md:col-span-3 text-right flex flex-col justify-center h-[42px] mt-6">
@@ -155,7 +146,7 @@
</div>
<div class="flex justify-end gap-4">
<a href="{{ route('sales.create') }}" class="px-6 py-2.5 text-gray-400 hover:text-white font-medium text-sm transition-colors flex items-center">
<a href="{{ route('sales.index') }}" class="px-6 py-2.5 text-gray-400 hover:text-white font-medium text-sm transition-colors flex items-center">
Cancelar
</a>
<button type="submit" class="px-8 py-2.5 bg-neon-lime text-neutral-900 font-bold rounded-lg hover:bg-[#b3e600] transition-colors shadow-lg shadow-neon-lime/20 transform hover:scale-105">
+233
View File
@@ -0,0 +1,233 @@
<x-layout title="Ingreso Taller">
<x-section-header subtitle="Taller" title="Nueva " highlight="Orden de Reparación" />
<x-ui.alert />
@if($errors->any())
<div class="w-120 bg-red-900/50 border border-red-500 text-red-300 px-4 py-3 rounded-lg mb-6 shadow-sm">
<ul class="list-disc list-inside">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="max-w-5xl mx-auto bg-panel-bg border border-neutral-800 rounded-xl p-8 shadow-lg">
<form action="{{ route('taller.store') }}" method="POST" class="space-y-8" id="taller-form">
@csrf
<!-- 1. Datos del Cliente -->
<div class="border-b border-neutral-800 pb-6">
<h3 class="text-white font-bold uppercase tracking-wider text-sm mb-4 flex items-center gap-2">
<span class="bg-neutral-800 text-neon-lime px-2 py-0.5 rounded text-xs">1</span> Cliente
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-xs font-bold text-gray-400 uppercase mb-2">Propietario</label>
<select name="client_id" class="w-full bg-neutral-900 border border-neutral-700 text-white rounded-lg p-2.5 focus:ring-neon-lime focus:border-neon-lime">
@foreach($clients as $client)
<option value="{{ $client->id }}">{{ $client->name }}</option>
@endforeach
</select>
<a href="{{ route('clients.create', ['origin' => 'taller']) }}" class="text-xs text-neon-lime hover:underline mt-1 inline-block">+ Nuevo Cliente</a>
</div>
<div>
<label class="block text-xs font-bold text-gray-400 uppercase mb-2">Teléfono Aviso</label>
<input type="text" name="contact_phone" placeholder="Ingresar numero de telefono" class="w-full bg-neutral-900 border border-neutral-700 text-white rounded-lg p-2.5 focus:ring-neon-lime focus:border-neon-lime">
</div>
</div>
</div>
<!-- 2. Diagnóstico y Repuestos -->
<div class="border-b border-neutral-800 pb-6">
<h3 class="text-white font-bold uppercase tracking-wider text-sm mb-4 flex items-center gap-2">
<span class="bg-neutral-800 text-neon-lime px-2 py-0.5 rounded text-xs">2</span> Diagnóstico y Repuestos
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Columna Izquierda: Datos Bici -->
<div class="space-y-4">
<div>
<label class="block text-xs font-bold text-gray-400 uppercase mb-2">Modelo de Bici / Color</label>
<input type="text" name="bike_model" required placeholder="Ej: Venzo Loki Roja R29" class="w-full bg-neutral-900 border border-neutral-700 text-white rounded-lg p-2.5 focus:ring-neon-lime focus:border-neon-lime">
</div>
<div>
<label class="block text-xs font-bold text-gray-400 uppercase mb-2">Problema / Servicio</label>
<textarea name="problem_description" rows="3" required class="w-full bg-neutral-900 border border-neutral-700 text-white rounded-lg p-2.5 focus:ring-neon-lime focus:border-neon-lime" placeholder="Ej: Service completo, hace ruido la caja..."></textarea>
</div>
</div>
<!-- Columna Derecha: Selector de Repuestos -->
<div class="bg-neutral-900/50 p-4 rounded-xl border border-neutral-800">
<label class="block text-xs font-bold text-neon-lime uppercase mb-2">Agregar Repuestos / Servicios</label>
<!-- Buscador -->
<div class="relative mb-3">
<input type="text" id="part-search" class="w-full bg-neutral-800 border border-neutral-700 text-white rounded-lg p-2 text-sm focus:ring-neon-lime focus:border-neon-lime" placeholder="Buscar repuesto..." autocomplete="off">
<!-- Lista desplegable de sugerencias -->
<div id="suggestions-box" class="absolute left-0 right-0 z-50 bg-neutral-800 border border-neutral-600 rounded-b-lg shadow-xl max-h-40 overflow-y-auto hidden"></div>
</div>
<!-- Lista Visual de Seleccionados -->
<div id="selected-parts-container" class="space-y-2 mb-3 min-h-13">
<p class="text-xs text-gray-600 italic text-center py-2" id="no-parts-msg">Sin repuestos seleccionados</p>
</div>
<!-- Input Oculto Real (Este es el que se envía a la BD) -->
<textarea name="parts_needed" id="parts_needed_real" class="hidden"></textarea>
</div>
</div>
</div>
<!-- 3. Agenda y Costos -->
<div>
<h3 class="text-white font-bold uppercase tracking-wider text-sm mb-4 flex items-center gap-2">
<span class="bg-neutral-800 text-neon-lime px-2 py-0.5 rounded text-xs">3</span> Acuerdo
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 items-end">
<div>
<label class="block text-xs font-bold text-gray-400 uppercase mb-2">Fecha Prometida / Retiro</label>
<input type="datetime-local" name="scheduled_at" required class="w-full bg-neutral-900 border border-neutral-700 text-white rounded-lg p-2.5 focus:ring-neon-lime focus:border-neon-lime">
</div>
<div class="bg-neutral-800 p-4 rounded-lg border border-neutral-700">
<label class="block text-xs font-bold text-gray-400 uppercase mb-1">Presupuesto Estimado</label>
<div class="flex items-center gap-2">
<span class="text-gray-500">$</span>
<!-- Input de costo: Se autocalcula pero el usuario puede editarlo manualmente -->
<input type="number" id="estimated_cost" name="estimated_cost" step="0.01" class="w-full bg-transparent border-0 text-white text-2xl font-black focus:ring-0 p-0" placeholder="0.00">
</div>
<p class="text-[10px] text-gray-500 mt-1">* Calculado automáticamente según repuestos. Editable.</p>
</div>
</div>
</div>
<div class="flex justify-end pt-4 border-t border-neutral-800">
<a href="{{ route('taller.index') }}" class="mr-4 px-6 py-3 text-gray-400 hover:text-white font-medium">Cancelar</a>
<button type="submit" class="px-8 py-3 bg-neon-lime text-neutral-900 font-bold rounded-lg hover:bg-[#b3e600] uppercase tracking-wide shadow-lg shadow-neon-lime/20">
Ingresar Bicicleta
</button>
</div>
</form>
</div>
<!-- Scripts para el Buscador de Repuestos -->
@push('scripts')
<script type="module">
const partsDB = @json($products);
const clientsDB = @json($clients);
let selectedParts = [];
$(document).ready(function() {
// Telefono de Cliente al cambiar selección
$('select[name="client_id"]').on('change', function() {
let clientId = $(this).val();
let client = clientsDB.find(c => c.id == clientId);
if (client && client.phone) {
$('input[name="contact_phone"]').val(client.phone);
} else {
$('input[name="contact_phone"]').val('');
}
});
// --- 1. Lógica del Buscador ---
$('#part-search').on('keyup focus', function() {
let term = $(this).val().toLowerCase();
let $box = $('#suggestions-box');
if (term.length === 0) {
$box.addClass('hidden').empty();
return;
}
let matches = partsDB.filter(p => p.name.toLowerCase().includes(term) || (p.sku && p.sku.toLowerCase().includes(term)));
let html = '';
if (matches.length > 0) {
matches.forEach(p => {
html += `
<div class="p-2 hover:bg-neutral-700 cursor-pointer text-xs text-white border-b border-neutral-700 last:border-0 suggestion-item flex justify-between items-center"
data-id="${p.id}" data-name="${p.name}" data-price="${p.price}">
<span>${p.name}</span>
<span class="text-neon-lime font-mono">$${p.price}</span>
</div>`;
});
} else {
html = '<div class="p-2 text-xs text-gray-500 italic">No encontrado</div>';
}
$box.html(html).removeClass('hidden');
});
// Ocultar sugerencias al hacer clic fuera
$(document).click(function(e) {
if (!$(e.target).closest('#part-search, #suggestions-box').length) {
$('#suggestions-box').addClass('hidden');
}
});
// --- 2. Agregar Repuesto ---
$(document).on('click', '.suggestion-item', function() {
let item = {
id: $(this).data('id'),
name: $(this).data('name'),
price: parseFloat($(this).data('price'))
};
// Agregar al array
selectedParts.push(item);
// Limpiar buscador
$('#part-search').val('').focus();
$('#suggestions-box').addClass('hidden');
renderList();
});
// --- 3. Eliminar Repuesto ---
window.removePart = function(index) {
selectedParts.splice(index, 1);
renderList();
};
// --- 4. Renderizar Lista y Calcular ---
function renderList() {
let $container = $('#selected-parts-container');
$container.empty();
let totalCost = 0;
let partsText = ""; // Texto para la BD
if (selectedParts.length === 0) {
$container.html('<p class="text-xs text-gray-600 italic text-center py-2" id="no-parts-msg">Sin repuestos seleccionados</p>');
} else {
selectedParts.forEach((p, index) => {
totalCost += p.price;
// Construimos texto para BD: "- Cámara ($5000)\n"
partsText += `- ${p.name} ($${p.price})\n`;
// Visual
$container.append(`
<div class="flex justify-between items-center bg-neutral-800 p-2 rounded border border-neutral-700 text-xs">
<div class="text-white">
${p.name}
<span class="text-gray-500 ml-1">($${p.price})</span>
</div>
<button type="button" onclick="removePart(${index})" class="text-red-500 hover:text-red-400 font-bold px-1">&times;</button>
</div>
`);
});
}
// Actualizar Inputs del Formulario
$('#estimated_cost').val(totalCost > 0 ? totalCost : ''); // Presupuesto
$('#parts_needed_real').val(partsText); // Texto para la BD
}
});
</script>
@endpush
</x-layout>
+61
View File
@@ -0,0 +1,61 @@
<x-layout title="Tablero de Taller">
<x-section-header subtitle="Gestión" title="Tablero de " highlight="Taller" />
@if(session('success'))
<div class="bg-green-900/50 border border-green-500 text-green-300 px-4 py-3 rounded-lg mb-6 shadow-sm">
{{ session('success') }}
</div>
@endif
<div class="flex w-full justify-end items-end mb-4">
<a href="{{ route('taller.create') }}" class="px-5 py-2.5 bg-neon-lime text-neutral-900 font-bold rounded-lg hover:bg-[#b3e600] uppercase tracking-wide text-xs flex items-center gap-2">
+ Ingresar Bici
</a>
</div>
<!-- Contenedor -->
<div class="flex flex-col lg:flex-row w-full gap-8 overflow-x-auto pb-4 h-[calc(100vh-250px)]">
<!-- COLUMNA 1 -->
<div class="flex-1 min-w-[300px] bg-neutral-900/50 border border-neutral-800 rounded-xl flex flex-col">
<div class="p-4 border-b border-neutral-800 bg-neutral-800/50 rounded-t-xl flex justify-between items-center">
<h3 class="font-bold text-gray-300 uppercase tracking-widest text-xs">🔴 Pendientes / A Revisar</h3>
<span class="bg-neutral-900 text-gray-400 text-xs px-2 py-1 rounded-full">{{ $pending->count() }}</span>
</div>
<div class="p-4 space-y-4 overflow-y-auto flex-1 custom-scrollbar">
@foreach($pending as $job)
<x-taller-card :job="$job" color="red" />
@endforeach
</div>
</div>
<!-- COLUMNA 2 -->
<div class="flex-1 min-w-[300px] bg-neutral-900/50 border border-neutral-800 rounded-xl flex flex-col">
<div class="p-4 border-b border-neutral-800 bg-neutral-800/50 rounded-t-xl flex justify-between items-center">
<h3 class="font-bold text-yellow-500 uppercase tracking-widest text-xs">🟡 En Reparación</h3>
<span class="bg-neutral-900 text-gray-400 text-xs px-2 py-1 rounded-full">{{ $inProgress->count() }}</span>
</div>
<div class="p-4 space-y-4 overflow-y-auto flex-1 custom-scrollbar">
@foreach($inProgress as $job)
<x-taller-card :job="$job" color="yellow" />
@endforeach
</div>
</div>
<!-- COLUMNA 3 -->
<div class="flex-1 min-w-[300px] bg-neutral-900/50 border border-neutral-800 rounded-xl flex flex-col">
<div class="p-4 border-b border-neutral-800 bg-neutral-800/50 rounded-t-xl flex justify-between items-center">
<h3 class="font-bold text-neon-lime uppercase tracking-widest text-xs">🟢 Listas para Retirar</h3>
<span class="bg-neutral-900 text-gray-400 text-xs px-2 py-1 rounded-full">{{ $ready->count() }}</span>
</div>
<div class="p-4 space-y-4 overflow-y-auto flex-1 custom-scrollbar">
@foreach($ready as $job)
<x-taller-card :job="$job" color="neon" />
@endforeach
</div>
</div>
</div>
</x-layout>