From 7c0313bc497fe7c43d3a2bdb0f8e9c11e687c72c Mon Sep 17 00:00:00 2001 From: Coassolo-Lucas Date: Sun, 17 Aug 2025 01:05:33 -0300 Subject: [PATCH 01/36] Agregue catalogo y un poco de vistaUsuario --- app/Http/Controllers/CatalogoController.php | 16 +++++++ app/Http/Controllers/ProductosController.php | 5 +++ resources/views/catalogo.blade.php | 43 ++++++++++++++++++- resources/views/dashboard.blade.php | 8 ++-- .../views/productos/vistaUsuario.blade.php | 12 ++++++ routes/web.php | 4 +- 6 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 app/Http/Controllers/CatalogoController.php create mode 100644 resources/views/productos/vistaUsuario.blade.php diff --git a/app/Http/Controllers/CatalogoController.php b/app/Http/Controllers/CatalogoController.php new file mode 100644 index 0000000..b7e5632 --- /dev/null +++ b/app/Http/Controllers/CatalogoController.php @@ -0,0 +1,16 @@ +delete(); return redirect(route('productos.index')); } + + public function vistaUsuario($id){ + $producto = Product::find($id); + return view('productos.vistaUsuario', compact('producto')); + } } diff --git a/resources/views/catalogo.blade.php b/resources/views/catalogo.blade.php index fa26743..3f718c4 100644 --- a/resources/views/catalogo.blade.php +++ b/resources/views/catalogo.blade.php @@ -1,6 +1,45 @@ - + +
+

CATÁLOGO

+ @if ($productos->count() > 0) +
+ @foreach ($productos as $prod) +
+ {{-- Imagen si existe --}} + @if (!empty($prod->imagen)) + {{ $prod->name }} + @else +
+ Sin imagen +
+ @endif + {{-- Nombre --}} +

{{ $prod->nombre }}

+ {{-- Descripción corta --}} + @if (!empty($prod->descripcion)) +

{{ $prod->descripcion }}

+ @endif - \ No newline at end of file + {{-- Precio --}} + @if (!empty($prod->precio)) +

${{ number_format($prod->precio, 2, ',', '.') }}

+ @endif + + {{-- Botón --}} + + Ver producto + + +
+ @endforeach +
+ @else +

No hay productos disponibles.

+ @endif +
+
diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index 1b0b21e..13ecb27 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -1,6 +1,8 @@ - -

BIENVENIDO {{Auth::user()->name}}

-
+ +

BIENVENIDO {{ Auth::user()->name }}

+ Ir a catalogo + @csrf +
diff --git a/resources/views/productos/vistaUsuario.blade.php b/resources/views/productos/vistaUsuario.blade.php new file mode 100644 index 0000000..fbcbba2 --- /dev/null +++ b/resources/views/productos/vistaUsuario.blade.php @@ -0,0 +1,12 @@ + +
+ Volver a catalogo +

Titulo: {{ $producto->nombre }}

+

+ Categoria: {{ $producto->Categoria }} +

+

+ {{ $producto->content }} +

+
+
diff --git a/routes/web.php b/routes/web.php index a3006d2..be3d780 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,6 +1,7 @@ group(function () { Route::delete('/productos/{id}', [ProductosController::class,'destroy'])->name('productos.destroy'); }); -Route::vieq('catalogo','catalogo')->name('catalogo'); \ No newline at end of file +Route::get('/catalogo', [CatalogoController::class,'catalogo'])->name('catalogo'); +Route::get('/productos/{id}/vistaUsuario', [ProductosController::class,'vistaUsuario'])->name('productos.vistaUsuario'); \ No newline at end of file From 01baa66213b5abf33dfbe5bc75764bad78ed66b0 Mon Sep 17 00:00:00 2001 From: Coassolo-Lucas Date: Wed, 20 Aug 2025 01:05:36 -0300 Subject: [PATCH 02/36] Agregue unique a email y errores a register. Y MERGE LO DE BRYAM (COPIE Y PEGUE) --- app/Http/Controllers/RegisterController.php | 2 +- resources/views/components/appc.blade.php | 77 ++++++++++----- resources/views/register.blade.php | 103 ++++++++++++-------- resources/views/welcome.blade.php | 24 +---- 4 files changed, 115 insertions(+), 91 deletions(-) diff --git a/app/Http/Controllers/RegisterController.php b/app/Http/Controllers/RegisterController.php index 7dc5bde..39f4fe1 100644 --- a/app/Http/Controllers/RegisterController.php +++ b/app/Http/Controllers/RegisterController.php @@ -13,7 +13,7 @@ class RegisterController extends Controller { $userData = $request->validate([ 'name' => ['required', 'string'], - 'email' => ['required', 'email'], + 'email' => ['required', 'email', 'unique:users,email'], 'password' => ['required', 'confirmed'] ]); diff --git a/resources/views/components/appc.blade.php b/resources/views/components/appc.blade.php index e249146..a19dcee 100644 --- a/resources/views/components/appc.blade.php +++ b/resources/views/components/appc.blade.php @@ -1,46 +1,69 @@ -{{-- @vite('resources/css/app.css') --}} +@props(['auth' => false]) - {{ $title ?? 'Lauck - Home' }} - @@ -52,7 +75,8 @@ Flowbite Logo Flowbite - From 68534a760345fdac8fa81a51504f9b0c2aee6a85 Mon Sep 17 00:00:00 2001 From: GianellaDelMestre <146126967+GianellaDelMestre@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:57:02 -0300 Subject: [PATCH 11/36] salecontroller en proceso creativo --- app/Http/Controllers/SaleController.php | 72 +++++++++++++++++++++++++ resources/views/sales/create.blade.php | 72 +++++++++++++++++++++++++ routes/web.php | 9 ++++ 3 files changed, 153 insertions(+) create mode 100644 app/Http/Controllers/SaleController.php create mode 100644 resources/views/sales/create.blade.php diff --git a/app/Http/Controllers/SaleController.php b/app/Http/Controllers/SaleController.php new file mode 100644 index 0000000..b96847f --- /dev/null +++ b/app/Http/Controllers/SaleController.php @@ -0,0 +1,72 @@ +', 0)->get(); + + // Retornamos la vista (que crearemos en el paso 4) pasando los productos + return view('sales.create', compact('products')); + } + + public function store(Request $request) + { + $request->validate([ + 'payment_method' => 'required|string', + 'items' => 'required|array', + 'items.*.product_id' => 'required|exists:products,id', + 'items.*.quantity' => 'required|integer|min:1', + ]); + + try { + DB::transaction(function () use ($request) { + $totalVenta = 0; + foreach ($request->items as $item) { + $producto = Product::find($item['product_id']); + $totalVenta += $producto->price * $item['quantity']; + + if ($producto->stock < $item['quantity']) { + throw new \Exception("No hay suficiente stock de " . $producto->name); + } + } + + // raro arreglar + $sale = Sale::create([ + 'user_id' => auth()->id(), // El empleado logueado + 'total' => $totalVenta, + 'payment_method' => $request->payment_method, + ]); + + foreach ($request->items as $item) { + $producto = Product::find($item['product_id']); + + SaleDetail::create([ + 'sale_id' => $sale->id, + 'product_id' => $producto->id, + 'quantity' => $item['quantity'], + 'price' => $producto->price, + ]); + $producto->decrement('stock', $item['quantity']); + } + }); + + // 5. REDIRECCIÓN DE ÉXITO + // Redirigimos al usuario con un mensaje flash [cite: 668] + return redirect()->route('sales.create')->with('success', '¡Venta registrada correctamente!'); + + } catch (\Exception $e) { + // Si algo falló (ej: falta stock), volvemos atrás con el error + return back()->with('error', 'Error en la venta: ' . $e->getMessage()); + } + } +} diff --git a/resources/views/sales/create.blade.php b/resources/views/sales/create.blade.php new file mode 100644 index 0000000..8af8f72 --- /dev/null +++ b/resources/views/sales/create.blade.php @@ -0,0 +1,72 @@ +@extends('layouts.app') + +@section('title', 'Nueva Venta') + +@section('main') +
+
+ +
+

Nueva Venta en Mostrador

+ + @if (session('success')) + + @endif + + @if (session('error')) + + @endif + +
+ @csrf + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+ + + + Cancelar + +
+
+
+
+
+@endsection \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index f819ba4..ab1325e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,7 @@ use App\Http\Controllers\AuthController; use App\Http\Controllers\CatalogoController; +use App\Http\Controllers\SaleController; use Illuminate\Support\Facades\Route; use App\Http\Controllers\HomeController; use App\Http\Controllers\LoginController; @@ -47,5 +48,13 @@ Route::middleware(['auth'])->group(function () { Route::delete('/productos/{id}', [ProductosController::class,'destroy'])->name('productos.destroy'); }); +Route::middleware(['auth'])->group(function () { + // mostrar + Route::get('/sales/create', [SaleController::class, 'create'])->name('sales.create'); + + // procesar + Route::post('/sales', [SaleController::class, 'store'])->name('sales.store'); +}); + Route::get('/catalogo', [CatalogoController::class,'catalogo'])->name('catalogo'); Route::get('/productos/{id}/vistaUsuario', [ProductosController::class,'vistaUsuario'])->name('productos.vistaUsuario'); From a40d43b631ece04c9df5db3752423f22f0461e4f Mon Sep 17 00:00:00 2001 From: BryamE Date: Tue, 9 Dec 2025 01:52:43 -0300 Subject: [PATCH 12/36] cambios para que ande el navbar --- app/Http/Controllers/SaleController.php | 2 +- resources/views/components/navbar.blade.php | 2 +- routes/web.php | 9 ++------- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/SaleController.php b/app/Http/Controllers/SaleController.php index 82cf09d..d0d63b2 100644 --- a/app/Http/Controllers/SaleController.php +++ b/app/Http/Controllers/SaleController.php @@ -13,7 +13,7 @@ class SaleController extends Controller public function create() { // Buscamos productos que tengan stock mayor a 0 para mostrar en el selector - $products = Product::where('stock', '>', 0)->get(); + $products = Product::where('stock_quantity', '>', 0)->get(); return view('sales.create', compact('products')); } diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index 6719c83..c8adb37 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -39,7 +39,7 @@ Taller
  • - Ventas diff --git a/routes/web.php b/routes/web.php index b10cec5..6740b18 100644 --- a/routes/web.php +++ b/routes/web.php @@ -8,7 +8,6 @@ use App\Http\Controllers\HomeController; use App\Http\Controllers\LoginController; use App\Http\Controllers\ProductosController; use App\Http\Controllers\RegisterController; -use App\Http\Controllers\SaleController; use App\Models\Product; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Session; @@ -48,16 +47,12 @@ Route::middleware(['auth'])->group(function () { Route::put('/productos/{id}',[ProductosController::class,'update'])->name('productos.update'); Route::delete('/productos/{id}', [ProductosController::class,'destroy'])->name('productos.destroy'); - Route::get('/sales', [SaleController::class, 'index'])->name('sales.index'); - Route::get('/sales/create', [SaleController::class, 'create'])->name('sales.create'); -}); - -Route::middleware(['auth'])->group(function () { // mostrar Route::get('/sales/create', [SaleController::class, 'create'])->name('sales.create'); - // procesar Route::post('/sales', [SaleController::class, 'store'])->name('sales.store'); + // Route::get('/sales', [SaleController::class, 'index'])->name('sales.index'); + // Route::get('/sales/create', [SaleController::class, 'create'])->name('sales.create'); }); Route::get('/catalogo', [CatalogoController::class,'catalogo'])->name('catalogo'); From 75ce7142b03881efd0bf71874f7e22a1465323b6 Mon Sep 17 00:00:00 2001 From: Bryam105 Date: Tue, 9 Dec 2025 11:13:02 -0330 Subject: [PATCH 13/36] cambio para compatibilidad --- app/Http/Controllers/SaleController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/SaleController.php b/app/Http/Controllers/SaleController.php index d0d63b2..27fa950 100644 --- a/app/Http/Controllers/SaleController.php +++ b/app/Http/Controllers/SaleController.php @@ -34,7 +34,7 @@ class SaleController extends Controller $producto = Product::find($item['product_id']); $totalVenta += $producto->price * $item['quantity']; - if ($producto->stock < $item['quantity']) { + if ($producto->stock_quantity < $item['quantity']) { throw new \Exception("No hay suficiente stock de " . $producto->name); } } From 03cc1fe7ad398894a4293a230b543296f05ee352 Mon Sep 17 00:00:00 2001 From: BryamE Date: Tue, 9 Dec 2025 13:38:14 -0300 Subject: [PATCH 14/36] del --- resources/a.md | 165 ------------------------------------------------- 1 file changed, 165 deletions(-) delete mode 100644 resources/a.md diff --git a/resources/a.md b/resources/a.md deleted file mode 100644 index ad025d6..0000000 --- a/resources/a.md +++ /dev/null @@ -1,165 +0,0 @@ -¡Perfecto\! Tus respuestas aclaran muchísimo el panorama. Al ser un sistema **Intranet (Local)** con un **Admin** y **Empleados** (visores/operadores), y con procesos manuales en el taller, podemos simplificar la arquitectura para lanzar un MVP (Producto Mínimo Viable) rápido y robusto, pero preparado para crecer. - -Aquí tienes la **Guía Maestra de Desarrollo para Lauck Systems**. - ------ - -### 1\. Arquitectura de Base de Datos (El Cimiento) - -Antes de escribir código, definamos las tablas. Laravel hace esto fácil con migraciones. - -#### Tablas Principales: - -1. **`users`** (Ya viene en Laravel) - - * Agregamos campo: `role` (enum: 'admin', 'employee'). - * *Lógica:* El Admin crea, edita y borra. El Empleado solo ve y registra ventas/turnos (según definas). - -2. **`clients`** (Clientes) - - * `name`, `phone` (clave para WhatsApp), `email`, `address`. - * *Nota:* Fundamental para agendar turnos y registrar garantías. - -3. **`products`** (Inventario Mixto) - - * `name`, `sku` (código único), `description`. - * `price` (precio venta), `cost` (costo, solo visible para admin). - * `stock_quantity` (entero). - * `min_stock_alert` (entero, para la alerta que pediste). - * `type` (enum: 'bike', 'accessory', 'service'). - * `serial_number` (nullable, solo para bicicletas). - -4. **`appointments`** (Turnos / Taller) - - * `client_id` (relación). - * `scheduled_at` (datetime - fecha y hora del turno). - * `bike_model` (texto libre, ej: "Venzo Loki 29"). - * `problem_description` (motivo de la consulta). - * `status` (enum: 'pending', 'confirmed', 'in\_progress', 'ready', 'delivered'). - * `notes` (uso interno del mecánico). - -5. **`sales`** (Ventas Internas / Historial) - - * `user_id` (quién vendió). - * `client_id` (opcional, si es consumidor final anónimo). - * `total_amount`. - * `payment_method` (efectivo, tarjeta, transferencia). - * `created_at` (fecha de venta). - -6. **`sale_items`** (Detalle de venta) - - * `sale_id`, `product_id`, `quantity`, `unit_price`. - ------ - -### 2\. Estructura de Rutas y Controladores (Backend) - -En Laravel, organizaremos esto por "Dominios". - - * **Autenticación:** (Ya lo tienes con Breeze/Jetstream). - * **DashboardController:** - * `index()`: Muestra las tarjetas, alertas de stock bajo (query simple `Product::whereColumn('stock', '<=', 'min_stock')->get()`) y turnos de hoy. - * **ProductController:** - * CRUD completo (Crear, Leer, Actualizar, Borrar). - * Función extra `search()`: Para el buscador de precios de los empleados. - * **ClientController:** - * CRUD simple. - * **AppointmentController (Gestión de Taller):** - * `calendar()`: Vista de calendario o lista cronológica. - * `statusUpdate()`: Para mover el turno de "Pendiente" a "Listo". - * **SaleController:** - * `create()`: Formulario para registrar una salida de mercadería. - * `store()`: Resta el stock y guarda la venta. - ------ - -### 3\. Componentes de UI (Frontend - Blade + Tailwind) - -Para mantener el estilo "Lauck" que ya definimos, necesitaremos crear estos componentes reutilizables (además de los que ya tienes): - -1. **`x-ui.status-badge`**: - * Una etiqueta pequeña redondeada que cambia de color según el estado (Verde para 'Stock Alto', Rojo para 'Sin Stock' o 'Turno Atrasado', Amarillo para 'En Reparación'). -2. **`x-ui.table`**: - * Una tabla estilizada con el modo oscuro, filas alternadas y cabeceras fijas. Vital para listas de precios y clientes. -3. **`x-forms.input` / `x-forms.select`**: - * Inputs con el estilo oscuro y borde neón al hacer foco, para no repetir las clases de Tailwind en cada formulario. -4. **`x-ui.alert`**: - * Para mostrar mensajes de éxito ("Producto guardado") o alertas ("¡Quedan solo 2 cámaras rodado 29\!"). - ------ - -### 4\. Funcionalidades Específicas a Implementar - -Aquí está la lógica para los requerimientos que mencionaste: - -#### A. Alertas de Stock ⚠️ - - * **Lógica:** No necesitas un sistema complejo de notificaciones en tiempo real todavía. - * **Implementación:** En el `DashboardController`, pasas una variable `$lowStockProducts` a la vista. - * **Vista:** En el Dashboard, si esa lista no está vacía, muestras una tarjeta roja o amarilla avisando "X productos con stock crítico". - -#### B. Consulta de Precios (Modo Solo Lectura) 🔍 - - * **Requerimiento:** Empleados consultan, no editan. - * **Implementación:** - * Crear una vista `products.checker`. - * Un input de búsqueda grande en el centro. - * Al escribir (AJAX o Livewire sería ideal aquí, pero un form simple con botón "Buscar" funciona), muestra una tarjeta gigante con el Nombre y el Precio. - * *Seguridad:* Usar **Laravel Gates** o **Policies**. - ```php - // En AuthServiceProvider - Gate::define('edit-products', function ($user) { - return $user->role === 'admin'; - }); - ``` - En Blade: `@can('edit-products') @endcan`. Así el empleado ve el producto pero no el botón de editar. - -#### C. Agenda de Turnos 📅 - - * **Lógica:** "Consulta -\> Cita". - * **Implementación:** - * No te compliques con un calendario visual complejo (tipo Google Calendar) al principio. - * Usa una **Lista Agrupada por Días**. - * *Ejemplo visual:* - * **HOY:** - * 09:00 - Jose (Pincharura) [Ver] - * 10:30 - Maria (Service General) [Ver] - * **MAÑANA:** - * ... - ------ - -### 5\. Roadmap Sugerido (Paso a Paso) - -Este es el orden lógico para programar sin perderse: - -1. **Semana 1: Cimientos y Stock (Lo más urgente)** - - * Configurar Migraciones (`products`, `clients`). - * Crear Modelos y Seeders (datos falsos para probar). - * Hacer el CRUD de Productos (Alta, Baja y Modificación). - * *Hito:* Poder cargar una bicicleta y verla en la lista. - -2. **Semana 2: Seguridad y Consultas** - - * Agregar campo `role` a Users. - * Crear la vista "Consulta de Precios" (solo lectura). - * Proteger las rutas de edición para que solo el Admin entre. - * *Hito:* El empleado puede loguearse y buscar un precio, pero no borrar nada. - -3. **Semana 3: El Taller (Turnos)** - - * Crear migración `appointments`. - * Crear formulario para "Nuevo Turno" (Seleccionar Cliente + Fecha + Motivo). - * Crear vista de "Lista de Turnos" en el Dashboard. - * *Hito:* Dejar de usar el cuaderno de papel para los turnos. - -4. **Semana 4: Refinamiento** - - * Alertas de stock visuales. - * Mejoras estéticas (Dark Mode en tablas). - * Pruebas finales en el servidor local. - -### ¿Cómo seguimos? - -¿Te gustaría que generemos el código para la **Migración de Productos** y el **Modelo**, o prefieres que diseñemos primero el componente visual de la **Tabla de Stock**? \ No newline at end of file From d71f33b0ed216b3ec93c54ef26ce0914623d6bc9 Mon Sep 17 00:00:00 2001 From: gianella Date: Tue, 9 Dec 2025 17:28:51 -0300 Subject: [PATCH 15/36] intento --- app/Http/Controllers/ClientController.php | 64 ++++++ app/Http/Controllers/SaleController.php | 35 +-- app/Models/Product.php | 11 +- app/Models/Sale.php | 7 +- app/Models/SaleDetail.php | 2 +- .../2025_12_06_193913_create_sales_table.php | 12 +- resources/views/clients/create.blade.php | 5 + resources/views/layouts/app.blade.php | 23 +- resources/views/sales/create.blade.php | 215 +++++++++++++++--- routes/web.php | 3 +- 10 files changed, 305 insertions(+), 72 deletions(-) create mode 100644 app/Http/Controllers/ClientController.php create mode 100644 resources/views/clients/create.blade.php diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php new file mode 100644 index 0000000..fcf5db8 --- /dev/null +++ b/app/Http/Controllers/ClientController.php @@ -0,0 +1,64 @@ +', 0)->get(); - - return view('sales.create', compact('products')); + + $clients = \App\Models\Client::orderBy('nombre')->get(); + + return view('sales.create', compact('products', 'clients')); } public function store(Request $request) { $request->validate([ 'payment_method' => 'required|string', + 'client_id' => 'nullable|exists:clients,id', 'items' => 'required|array', 'items.*.product_id' => 'required|exists:products,id', 'items.*.quantity' => 'required|integer|min:1', @@ -30,32 +35,36 @@ class SaleController extends Controller try { DB::transaction(function () use ($request) { $totalVenta = 0; + foreach ($request->items as $item) { - $producto = Product::find($item['product_id']); - $totalVenta += $producto->price * $item['quantity']; + $product = Product::find($item['product_id']); + $totalVenta += $product->precio * $item['quantity']; - if ($producto->stock < $item['quantity']) { - throw new \Exception("No hay suficiente stock de " . $producto->name); + if ($product->stock < $item['quantity']) { + throw new \Exception("No hay suficiente stock de " . $product->nombre); } } - // raro arreglar + //cabecera $sale = Sale::create([ - 'user_id' => auth()->id(), // El empleado logueado + //'user_id' => auth()->id(), //empleado logueado + 'client_id' => $request->client_id, 'total' => $totalVenta, 'payment_method' => $request->payment_method, ]); foreach ($request->items as $item) { - $producto = Product::find($item['product_id']); + $product = Product::find($item['product_id']); SaleDetail::create([ 'sale_id' => $sale->id, - 'product_id' => $producto->id, - 'quantity' => $item['quantity'], - 'price' => $producto->price, + 'product_id' => $product->id, + 'cantidad' => $item['quantity'], + 'precio' => $product->precio, ]); - $producto->decrement('stock', $item['quantity']); + $nuevoStock = $product->stock - $item['quantity']; + $product->stock = $nuevoStock; + $product->save(); } }); diff --git a/app/Models/Product.php b/app/Models/Product.php index a4e3f49..9165684 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -8,16 +8,7 @@ use Illuminate\Database\Eloquent\Model; class Product extends Model { use HasFactory; - protected $fillable = [ - 'codigo', - 'nombre', - 'costo', - 'precio', - 'stock', - 'min_stock', - 'categoria', - 'descripcion' - ]; + protected $guarded = []; public function supplier() { return $this->belongsTo(Suppliers::class); diff --git a/app/Models/Sale.php b/app/Models/Sale.php index c9c88ad..aeeca90 100644 --- a/app/Models/Sale.php +++ b/app/Models/Sale.php @@ -3,13 +3,10 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; - +use Illuminate\Database\Eloquent\Factories\HasFactory; class Sale extends Model { - use HasFactory; - protected $fillable = [ - 'metodo_pago' - ]; + //use HasFactory; // Permitimos asignación masiva para poder guardar rápido protected $guarded = []; diff --git a/app/Models/SaleDetail.php b/app/Models/SaleDetail.php index bbe36e6..597eff4 100644 --- a/app/Models/SaleDetail.php +++ b/app/Models/SaleDetail.php @@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Model; class SaleDetail extends Model { - use HasFactory; + //use HasFactory; protected $guarded = []; // este detalle pertenece a una Venta específica diff --git a/database/migrations/2025_12_06_193913_create_sales_table.php b/database/migrations/2025_12_06_193913_create_sales_table.php index b0bfc22..2125264 100644 --- a/database/migrations/2025_12_06_193913_create_sales_table.php +++ b/database/migrations/2025_12_06_193913_create_sales_table.php @@ -13,13 +13,11 @@ return new class extends Migration { Schema::create('sales', function (Blueprint $table) { $table->id(); - // 1. Cliente que compra - $table->foreignId('user_id')->constrained()->onDelete('cascade'); - // 2. Datos generales de la venta - $table->decimal('total', 10, 2); // Total final del ticket - $table->string('metodo_pago'); // Ej: "Efectivo", "Tarjeta", "MercadoPago" - //capaz van mas datos ni idea - // 3. Fecha y Hora (created_at servirá como fecha de venta) + //$table->foreignId('user_id')->constrained(); + // nullable para que no sea obligatrio + $table->foreignId('client_id')->nullable()->constrained(); + $table->decimal('total', 10, 2); + $table->string('payment_method'); $table->timestamps(); }); } diff --git a/resources/views/clients/create.blade.php b/resources/views/clients/create.blade.php new file mode 100644 index 0000000..6265ad0 --- /dev/null +++ b/resources/views/clients/create.blade.php @@ -0,0 +1,5 @@ +@extends('layouts.app') +@section('main') +

    formulario de crear cliente

    + +@endsection \ No newline at end of file diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 67c46ad..4b2d15f 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -3,15 +3,28 @@ - - @yield('title','Lauck - Home') + + + + @yield('title','Lauck - Home') -
    Cabeza
    +
    +

    Lauck Bicicletería

    +
    - @yield('main') +
    + @yield('main') +
    -
    Pies
    +
    + © {{ date('Y') }} Sistema Lauck +
    + + + + + @stack('scripts') \ No newline at end of file diff --git a/resources/views/sales/create.blade.php b/resources/views/sales/create.blade.php index 8af8f72..fd20768 100644 --- a/resources/views/sales/create.blade.php +++ b/resources/views/sales/create.blade.php @@ -7,44 +7,102 @@
    -

    Nueva Venta en Mostrador

    +
    +

    Nueva Venta en Mostrador

    +
    @if (session('success')) - + +@push('scripts') + +@endpush @endsection \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index b10cec5..4308583 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,12 +3,12 @@ use App\Http\Controllers\AuthController; use App\Http\Controllers\CatalogoController; use App\Http\Controllers\SaleController; +use App\Http\Controllers\ClientController; use Illuminate\Support\Facades\Route; use App\Http\Controllers\HomeController; use App\Http\Controllers\LoginController; use App\Http\Controllers\ProductosController; use App\Http\Controllers\RegisterController; -use App\Http\Controllers\SaleController; use App\Models\Product; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Session; @@ -50,6 +50,7 @@ Route::middleware(['auth'])->group(function () { Route::get('/sales', [SaleController::class, 'index'])->name('sales.index'); Route::get('/sales/create', [SaleController::class, 'create'])->name('sales.create'); + Route::resource('clients', ClientController::class); }); Route::middleware(['auth'])->group(function () { From 38d44f58a674ea9bb397852e2f0bbce4ea3dcd3f Mon Sep 17 00:00:00 2001 From: BryamE Date: Tue, 9 Dec 2025 18:21:07 -0300 Subject: [PATCH 16/36] Standarizando archivos --- app/Http/Controllers/CatalogoController.php | 4 ++-- app/Http/Controllers/SaleController.php | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/CatalogoController.php b/app/Http/Controllers/CatalogoController.php index e74a30a..f41ac4a 100644 --- a/app/Http/Controllers/CatalogoController.php +++ b/app/Http/Controllers/CatalogoController.php @@ -10,8 +10,8 @@ class CatalogoController extends Controller public function catalogo() { - $productos = Product::all(); - return view('catalogo', compact('productos')); + $products = Product::all(); + return view('catalogo', compact('products')); } /** diff --git a/app/Http/Controllers/SaleController.php b/app/Http/Controllers/SaleController.php index aedf1ba..b954b1a 100644 --- a/app/Http/Controllers/SaleController.php +++ b/app/Http/Controllers/SaleController.php @@ -15,9 +15,9 @@ class SaleController extends Controller public function create() { // Buscamos productos que tengan stock mayor a 0 para mostrar en el selector - $products = Product::where('stock', '>', 0)->get(); + $products = Product::where('stock_quantity', '>', 0)->get(); - $clients = \App\Models\Client::orderBy('nombre')->get(); + $clients = \App\Models\Client::orderBy('name')->get(); return view('sales.create', compact('products', 'clients')); } @@ -34,13 +34,13 @@ class SaleController extends Controller try { DB::transaction(function () use ($request) { - $totalVenta = 0; + $totalSale = 0; foreach ($request->items as $item) { $product = Product::find($item['product_id']); - $totalVenta += $product->precio * $item['quantity']; + $totalSale += $product->precio * $item['quantity']; - if ($product->stock < $item['quantity']) { + if ($product->stock_quantity < $item['quantity']) { throw new \Exception("No hay suficiente stock de " . $product->nombre); } } @@ -49,7 +49,7 @@ class SaleController extends Controller $sale = Sale::create([ //'user_id' => auth()->id(), //empleado logueado 'client_id' => $request->client_id, - 'total' => $totalVenta, + 'total' => $totalSale, 'payment_method' => $request->payment_method, ]); @@ -60,10 +60,10 @@ class SaleController extends Controller 'sale_id' => $sale->id, 'product_id' => $product->id, 'cantidad' => $item['quantity'], - 'precio' => $product->precio, + 'precio' => $product->price, ]); - $nuevoStock = $product->stock - $item['quantity']; - $product->stock = $nuevoStock; + $nuevoStock = $product->stock_quantity - $item['quantity']; + $product->stock_quantity = $nuevoStock; $product->save(); } }); From 5d12ec10a32ceb78ae3940384aaf6eabe3b79f46 Mon Sep 17 00:00:00 2001 From: BryamE Date: Tue, 9 Dec 2025 19:44:20 -0300 Subject: [PATCH 17/36] Terminadas standarizaciones --- app/Http/Controllers/ProductosController.php | 18 +- app/Http/Controllers/SaleController.php | 4 +- app/Models/Product.php | 3 +- app/Models/Supplier.php | 7 +- app/View/Components/Alert2.php | 40 --- ...25_12_06_182356_create_suppliers_table.php | 4 +- ...2025_12_06_184833_create_clients_table.php | 30 --- ...12_06_201853_create_sale_details_table.php | 4 +- ...12_07_023045_create_appointments_table.php | 33 --- resources/views/productos/show.blade.php | 8 +- resources/views/sales/create.blade.php | 232 +++++++++--------- routes/web.php | 5 +- 12 files changed, 136 insertions(+), 252 deletions(-) delete mode 100644 app/View/Components/Alert2.php delete mode 100644 database/migrations/2025_12_06_184833_create_clients_table.php delete mode 100644 database/migrations/2025_12_07_023045_create_appointments_table.php diff --git a/app/Http/Controllers/ProductosController.php b/app/Http/Controllers/ProductosController.php index d288937..76fb067 100644 --- a/app/Http/Controllers/ProductosController.php +++ b/app/Http/Controllers/ProductosController.php @@ -73,28 +73,28 @@ class ProductosController extends Controller * Muestra el detalle de un producto. * Usamos Route Model Binding: Laravel busca el ID solo. */ - public function show(Product $producto) + public function show(Product $product) { - return view('productos.show', compact('producto')); + return view('productos.show', compact('product')); } /** * Muestra el formulario de edición. */ - public function edit(Product $producto) + public function edit(Product $product) { - return view('productos.edit', compact('producto')); + return view('productos.edit', compact('product')); } /** * Actualiza el producto existente. */ - public function update(Request $request, Product $producto) + public function update(Request $request, Product $product) { $validated = $request->validate([ 'name' => 'required|string|max:255', // Validamos que el SKU sea único PERO ignoramos el ID de este producto actual - 'sku' => ['nullable', 'string', Rule::unique('products')->ignore($producto->id)], + 'sku' => ['nullable', 'string', Rule::unique('products')->ignore($product->id)], 'description' => 'nullable|string', 'price' => 'required|numeric|min:0', 'cost' => 'nullable|numeric|min:0', @@ -104,7 +104,7 @@ class ProductosController extends Controller 'serial_number' => 'nullable|string|max:100', ]); - $producto->update($validated); + $product->update($validated); return redirect()->route('productos.index') ->with('success', 'Producto actualizado exitosamente.'); @@ -113,9 +113,9 @@ class ProductosController extends Controller /** * Elimina el producto. */ - public function destroy(Product $producto) + public function destroy(Product $product) { - $producto->delete(); + $product->delete(); return redirect()->route('productos.index') ->with('success', 'Producto eliminado.'); } diff --git a/app/Http/Controllers/SaleController.php b/app/Http/Controllers/SaleController.php index b954b1a..8e8a7f7 100644 --- a/app/Http/Controllers/SaleController.php +++ b/app/Http/Controllers/SaleController.php @@ -59,8 +59,8 @@ class SaleController extends Controller SaleDetail::create([ 'sale_id' => $sale->id, 'product_id' => $product->id, - 'cantidad' => $item['quantity'], - 'precio' => $product->price, + 'quantity' => $item['quantity'], + 'price' => $product->price, ]); $nuevoStock = $product->stock_quantity - $item['quantity']; $product->stock_quantity = $nuevoStock; diff --git a/app/Models/Product.php b/app/Models/Product.php index 25d29cf..f9ce056 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -13,13 +13,12 @@ class Product extends Model public function hasLowStock(): bool { - //cambiar return $this->stock_quantity <= $this->min_stock_alert; } public function supplier() { - return $this->belongsTo(Suppliers::class); + return $this->belongsTo(Supplier::class); } // Opción 1: Relación directa con los detalles (Renglones de ticket) diff --git a/app/Models/Supplier.php b/app/Models/Supplier.php index 8acf047..c72f08a 100644 --- a/app/Models/Supplier.php +++ b/app/Models/Supplier.php @@ -6,11 +6,8 @@ use Illuminate\Database\Eloquent\Model; class Supplier extends Model { - protected $fillable = [ - 'nombre', - 'telefono', - 'email' - ]; + protected $fillable = [ 'name', 'phone', 'email' ]; + public function products() { return $this->hasMany(Product::class); diff --git a/app/View/Components/Alert2.php b/app/View/Components/Alert2.php deleted file mode 100644 index bf1d9bb..0000000 --- a/app/View/Components/Alert2.php +++ /dev/null @@ -1,40 +0,0 @@ -class = $class; - } - - //* Get the view / contents that represent the component. - public function render(): View|Closure|string - { - return view('components.alert2'); - } -} diff --git a/database/migrations/2025_12_06_182356_create_suppliers_table.php b/database/migrations/2025_12_06_182356_create_suppliers_table.php index c5e0c12..ed43605 100644 --- a/database/migrations/2025_12_06_182356_create_suppliers_table.php +++ b/database/migrations/2025_12_06_182356_create_suppliers_table.php @@ -13,8 +13,8 @@ return new class extends Migration { Schema::create('suppliers', function (Blueprint $table) { $table->id(); - $table->string('nombre'); - $table->string('telefono'); + $table->string('name'); + $table->string('phone'); $table->string('email'); $table->timestamps(); }); diff --git a/database/migrations/2025_12_06_184833_create_clients_table.php b/database/migrations/2025_12_06_184833_create_clients_table.php deleted file mode 100644 index 398e55b..0000000 --- a/database/migrations/2025_12_06_184833_create_clients_table.php +++ /dev/null @@ -1,30 +0,0 @@ -id(); - $table->string('nombre'); - $table->string('telefono'); - $table->string('email'); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('clients'); - } -}; diff --git a/database/migrations/2025_12_06_201853_create_sale_details_table.php b/database/migrations/2025_12_06_201853_create_sale_details_table.php index e357fa9..3e0818a 100644 --- a/database/migrations/2025_12_06_201853_create_sale_details_table.php +++ b/database/migrations/2025_12_06_201853_create_sale_details_table.php @@ -15,8 +15,8 @@ return new class extends Migration $table->id(); $table->foreignId('sale_id')->constrained()->onDelete('cascade'); $table->foreignId('product_id')->constrained(); - $table->integer('cantidad'); - $table->decimal('precio', 10, 2); + $table->integer('quantity'); + $table->decimal('price', 10, 2); $table->timestamps(); }); } diff --git a/database/migrations/2025_12_07_023045_create_appointments_table.php b/database/migrations/2025_12_07_023045_create_appointments_table.php deleted file mode 100644 index 3bac73b..0000000 --- a/database/migrations/2025_12_07_023045_create_appointments_table.php +++ /dev/null @@ -1,33 +0,0 @@ -id(); - $table->foreignId('client_id')->constrained(); - $table->datetime('fecha_programada'); - $table->string('modelo_bici')->nullable(); - $table->string('descripcion')->nullable(); - $table->string('estado')->default('pendiente'); - $table->string('notas')->nullable(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('appointments'); - } -}; diff --git a/resources/views/productos/show.blade.php b/resources/views/productos/show.blade.php index 71bb8b7..b74c74f 100644 --- a/resources/views/productos/show.blade.php +++ b/resources/views/productos/show.blade.php @@ -47,10 +47,4 @@
    - - - {{-- componente alerta --}} - {{-- - Jose! - Lorem ipsum dolor sit amet consectetur adipisicing elit. Libero, vel omnis - --}} \ No newline at end of file + \ No newline at end of file diff --git a/resources/views/sales/create.blade.php b/resources/views/sales/create.blade.php index fd20768..843616c 100644 --- a/resources/views/sales/create.blade.php +++ b/resources/views/sales/create.blade.php @@ -1,131 +1,128 @@ -@extends('layouts.app') - -@section('title', 'Nueva Venta') - -@section('main') -
    -
    - -
    -
    -

    Nueva Venta en Mostrador

    -
    - - @if (session('success')) -
    - ¡Éxito! {{ session('success') }} -
    - @endif - - @if (session('error')) -
    - Error: {{ session('error') }} -
    - @endif + +
    +
    - @if ($errors->any()) -
    -
      - @foreach ($errors->all() as $error) -
    • • {{ $error }}
    • - @endforeach -
    +
    +
    +

    Nueva Venta en Mostrador

    - @endif - - - -
    - @csrf - -
    - -
    - - - - + - + + @if (session('success')) +
    + ¡Éxito! {{ session('success') }}
    -
    - -
    -
    -
    - - + + @foreach($clients as $client) + @endforeach -
    - -
    - - -
    - -
    - $0.00 -
    - -
    - + + + + +
    -
    - -
    - -
    - -
    -
    - Total a Pagar: $0.00 + +
    +
    +
    + + +
    + +
    + + +
    + +
    + $0.00 +
    + +
    + +
    +
    -
    - -
    -
    - - -
    - -
    - - Cancelar - -
    -
    - + +
    +
    + Total a Pagar: $0.00 +
    +
    + +
    +
    + + +
    + +
    + + Cancelar + + +
    +
    + +
    -
    + @push('scripts') -@endpush -@endsection \ No newline at end of file +@endpush \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index bd87c32..d243303 100644 --- a/routes/web.php +++ b/routes/web.php @@ -43,12 +43,13 @@ Route::middleware(['auth'])->group(function () { Route::resource('productos', ProductosController::class)->parameters([ 'productos' => 'producto' ]); + Route::resource('clients', ClientController::class); + Route::get('/checker', [ProductosController::class, 'checker'])->name('productos.checker'); Route::get('/productos/{id}', [ProductosController::class,'show'])->name('productos.show'); Route::get('/productos/{id}/edit', [ProductosController::class,'edit'])->name('productos.edit'); - Route::get('/checker', [ProductosController::class, 'checker'])->name('productos.checker'); + //Route::get('/sales', [SaleController::class, 'index'])->name('sales.index'); Route::get('/sales/create', [SaleController::class, 'create'])->name('sales.create'); - Route::resource('clients', ClientController::class); }); From 6e7fc2367faf05def52ffb9e1aa91eb25a16148d Mon Sep 17 00:00:00 2001 From: BryamE Date: Tue, 9 Dec 2025 19:54:15 -0300 Subject: [PATCH 18/36] finally.... --- resources/views/catalogo.blade.php | 4 ++-- resources/views/productos/edit.blade.php | 22 +++++++++++----------- resources/views/sales/create.blade.php | 2 +- routes/web.php | 5 +++-- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/resources/views/catalogo.blade.php b/resources/views/catalogo.blade.php index 3f718c4..3538fd1 100644 --- a/resources/views/catalogo.blade.php +++ b/resources/views/catalogo.blade.php @@ -2,9 +2,9 @@

    CATÁLOGO

    - @if ($productos->count() > 0) + @if ($products->count() > 0)
    - @foreach ($productos as $prod) + @foreach ($products as $prod)
    {{-- Imagen si existe --}} @if (!empty($prod->imagen)) diff --git a/resources/views/productos/edit.blade.php b/resources/views/productos/edit.blade.php index 5e7752f..fc58a00 100644 --- a/resources/views/productos/edit.blade.php +++ b/resources/views/productos/edit.blade.php @@ -1,44 +1,44 @@ Lauck - Editar - Editar - {{$producto->nombre}} + Editar - {{$product->nombre}}
    -
    + @csrf @method('PUT')
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - 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"/> + 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"/>
    @@ -46,7 +46,7 @@ - + Volver
    diff --git a/resources/views/sales/create.blade.php b/resources/views/sales/create.blade.php index 843616c..26ec74a 100644 --- a/resources/views/sales/create.blade.php +++ b/resources/views/sales/create.blade.php @@ -110,7 +110,7 @@
    - + Cancelar
    + + +
    + {{ $products->links() }} +
    diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index 22715e9..61a108a 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -21,31 +21,68 @@
    diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index e412c1e..30bd4af 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -1,4 +1,2 @@ - - Lauck - Inicio - Bienvenido - + + From ffe39d8d9805bc5abd76f7481dbc7ef5ac2d9003 Mon Sep 17 00:00:00 2001 From: BryamE Date: Thu, 11 Dec 2025 13:03:22 -0300 Subject: [PATCH 23/36] Cambios en vistas de catalogo, mejoras visuales y creado componente para ver el producto como invitado --- resources/views/catalogo.blade.php | 3 +- .../views/components/ui/imgcard.blade.php | 31 +++++++++++++++++++ resources/views/welcome.blade.php | 18 ++++++++--- routes/web.php | 2 +- 4 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 resources/views/components/ui/imgcard.blade.php diff --git a/resources/views/catalogo.blade.php b/resources/views/catalogo.blade.php index 3a4eecc..1b47400 100644 --- a/resources/views/catalogo.blade.php +++ b/resources/views/catalogo.blade.php @@ -8,7 +8,8 @@ @if ($products->count() > 0)
    @foreach ($products as $prod) -
    + +
    {{-- Imagen si existe --}} @if (!empty($prod->img)) {{ $prod->name }} '#', 'title', 'description', 'price', 'image' => null]) + +
    + {{-- Imagen si existe --}} + @if ($image) + {{ $title }} + @else +
    + Sin imagen +
    + @endif + + {{-- Nombre --}} +

    {{ $title }}

    + + {{-- Descripción corta --}} +
    + @if (!empty($description)) +

    {{ $description }}

    + @endif +
    + + {{-- Precio --}} +

    ${{ number_format($price, 2, ',', '.') }}

    + + {{-- Botón --}} + + Ver producto + +
    \ No newline at end of file diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index e412c1e..05b8208 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -1,4 +1,14 @@ - - Lauck - Inicio - Bienvenido - + + + + + + \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index db78519..f416a7c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -14,6 +14,7 @@ use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Session; Route::get('/',HomeController::class); +Route::get('/catalogo', [CatalogoController::class,'catalogo'])->name('catalogo'); Route::get('login', function(){ return view('login'); @@ -52,5 +53,4 @@ Route::middleware(['auth'])->group(function () { }); -Route::get('/catalogo', [CatalogoController::class,'catalogo'])->name('catalogo'); Route::get('/productos/{id}/vistaUsuario', [ProductosController::class,'vistaUsuario'])->name('productos.vistaUsuario'); \ No newline at end of file From 59ebbee5e60aa91970cd2e45796f75bd47c2e09e Mon Sep 17 00:00:00 2001 From: BryamE Date: Fri, 12 Dec 2025 00:37:59 -0300 Subject: [PATCH 24/36] INSTALE TAILWIND Y JQUERY GENTE --- package-lock.json | 2554 +++++++++++++++++++ package.json | 10 +- postcss.config.js | 6 + resources/css/app.css | 49 +- resources/js/bootstrap.js | 7 + resources/views/catalogo.blade.php | 6 - resources/views/components/layout.blade.php | 33 +- tailwind.config.js | 22 + 8 files changed, 2642 insertions(+), 45 deletions(-) create mode 100644 package-lock.json create mode 100644 postcss.config.js create mode 100644 tailwind.config.js diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1f1aba3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2554 @@ +{ + "name": "ProyectoLauck", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@tailwindcss/postcss": "^4.1.18", + "jquery": "^3.7.1" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.18", + "autoprefixer": "^10.4.22", + "axios": "^1.8.2", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^2.0.0", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.18", + "vite": "^7.0.4" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", + "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", + "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", + "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", + "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", + "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", + "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", + "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", + "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", + "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", + "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", + "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", + "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", + "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", + "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", + "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", + "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", + "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", + "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", + "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", + "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", + "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", + "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", + "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", + "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.0", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz", + "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz", + "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "postcss": "^8.4.41", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.18.tgz", + "integrity": "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "tailwindcss": "4.1.18" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.4.22", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.22.tgz", + "integrity": "sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.27.0", + "caniuse-lite": "^1.0.30001754", + "fraction.js": "^5.3.4", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.6.tgz", + "integrity": "sha512-v9BVVpOTLB59C9E7aSnmIF8h7qRsFpx+A2nugVMTszEOMcfjlZMsXRm4LF23I3Z9AJxc8ANpIvzbzONoX9VJlg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001760", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", + "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "license": "MIT" + }, + "node_modules/laravel-vite-plugin": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-2.0.1.tgz", + "integrity": "sha512-zQuvzWfUKQu9oNVi1o0RZAJCwhGsdhx4NEOyrVQwJHaWDseGP9tl7XUPLY2T8Cj6+IrZ6lmyxlR1KC8unf3RLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "vite-plugin-full-reload": "^1.1.0" + }, + "bin": { + "clean-orphaned-assets": "bin/clean.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^7.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", + "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.53.3", + "@rollup/rollup-android-arm64": "4.53.3", + "@rollup/rollup-darwin-arm64": "4.53.3", + "@rollup/rollup-darwin-x64": "4.53.3", + "@rollup/rollup-freebsd-arm64": "4.53.3", + "@rollup/rollup-freebsd-x64": "4.53.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", + "@rollup/rollup-linux-arm-musleabihf": "4.53.3", + "@rollup/rollup-linux-arm64-gnu": "4.53.3", + "@rollup/rollup-linux-arm64-musl": "4.53.3", + "@rollup/rollup-linux-loong64-gnu": "4.53.3", + "@rollup/rollup-linux-ppc64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-musl": "4.53.3", + "@rollup/rollup-linux-s390x-gnu": "4.53.3", + "@rollup/rollup-linux-x64-gnu": "4.53.3", + "@rollup/rollup-linux-x64-musl": "4.53.3", + "@rollup/rollup-openharmony-arm64": "4.53.3", + "@rollup/rollup-win32-arm64-msvc": "4.53.3", + "@rollup/rollup-win32-ia32-msvc": "4.53.3", + "@rollup/rollup-win32-x64-gnu": "4.53.3", + "@rollup/rollup-win32-x64-msvc": "4.53.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "devOptional": true, + "license": "0BSD" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", + "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "7.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.7.tgz", + "integrity": "sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-full-reload": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz", + "integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "picomatch": "^2.3.1" + } + }, + "node_modules/vite-plugin-full-reload/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/package.json b/package.json index 34c62c7..385e02e 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,17 @@ "dev": "vite" }, "devDependencies": { - "@tailwindcss/vite": "^4.0.0", + "@tailwindcss/vite": "^4.1.18", + "autoprefixer": "^10.4.22", "axios": "^1.8.2", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0.0", - "tailwindcss": "^4.0.0", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.18", "vite": "^7.0.4" + }, + "dependencies": { + "@tailwindcss/postcss": "^4.1.18", + "jquery": "^3.7.1" } } diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..34d4d9f --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {}, + }, +}; \ No newline at end of file diff --git a/resources/css/app.css b/resources/css/app.css index c198cf5..24bd901 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,17 +1,52 @@ -@import 'tailwindcss'; +/* 1. Importar fuente Montserrat */ +@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;800&display=swap'); +/* 2. Importar Tailwind (v4) */ +@import "tailwindcss"; @source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; @source '../../storage/framework/views/*.php'; @source '../**/*.blade.php'; @source '../**/*.js'; +/* 3. Configuración del Tema (NUEVO EN v4) */ @theme { - --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; + /* Definimos el color personalizado 'dark-bg' */ + --color-dark-bg: #121212; + /* TRADUCCIÓN: fontFamily: { sans: [...] } */ + --font-sans: 'Montserrat', sans-serif; + + /* TRADUCCIÓN: colors: { ... } + La sintaxis es: --color-nombre-del-color: valor; + */ + --color-neon-lime: #ccff00; + --color-dark-bg: #1a1a1a; + --color-panel-bg: #242424; } -@keyframes gradientMove { - 0%{ background-position: 0% 50%;} - 50%{ background-position: 100% 50%;} - 100%{ background-position: 0% 50%;} +/* 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-size: 40px 40px; + background-position: center; } + +/* 5. Personalización del Scrollbar */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: #1a1a1a; +} + +::-webkit-scrollbar-thumb { + background: #444; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: #ccff00; /* Verde Neón */ +} \ No newline at end of file diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js index 5f1390b..6c675bf 100644 --- a/resources/js/bootstrap.js +++ b/resources/js/bootstrap.js @@ -2,3 +2,10 @@ import axios from 'axios'; window.axios = axios; window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; + +/** + * Configuración de jQuery global (window.$) + */ +import jQuery from 'jquery'; +window.$ = jQuery; +window.jQuery = jQuery; diff --git a/resources/views/catalogo.blade.php b/resources/views/catalogo.blade.php index 4682d14..30a4fa7 100644 --- a/resources/views/catalogo.blade.php +++ b/resources/views/catalogo.blade.php @@ -8,7 +8,6 @@ @if ($products->count() > 0)
    @foreach ($products as $prod) -
    {{-- Imagen si existe --}} @if (!empty($prod->img)) @@ -48,9 +47,4 @@

    No hay productos disponibles.

    @endif
    - - -
    - {{ $products->links() }} -
    diff --git a/resources/views/components/layout.blade.php b/resources/views/components/layout.blade.php index fe1729b..7f5147b 100644 --- a/resources/views/components/layout.blade.php +++ b/resources/views/components/layout.blade.php @@ -6,41 +6,14 @@ {{ $title ?? 'Lauck Dashboard' }} - - - - - - - + + @vite(['resources/css/app.css', 'resources/js/app.js']) -
    +
    diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..20be7ba --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,22 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./resources/**/*.blade.php", + "./resources/**/*.js", + "./resources/**/*.vue", + ], + theme: { + extend: { + fontFamily: { + sans: ['Montserrat', 'sans-serif'], // Define Montserrat como fuente principal + }, + colors: { + // Tus colores personalizados + 'neon-lime': '#ccff00', + 'dark-bg': '#1a1a1a', + 'panel-bg': '#242424', + } + }, + }, + plugins: [], +} \ No newline at end of file From 39cb070b6a7ef47ca3bc43393fa9555d89a894c9 Mon Sep 17 00:00:00 2001 From: BryamE Date: Fri, 19 Dec 2025 22:11:41 -0300 Subject: [PATCH 25/36] COSITAS --- database/factories/ProductFactory.php | 4 +++- database/seeders/DatabaseSeeder.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/database/factories/ProductFactory.php b/database/factories/ProductFactory.php index 8cbc82a..2c53073 100644 --- a/database/factories/ProductFactory.php +++ b/database/factories/ProductFactory.php @@ -18,7 +18,9 @@ class ProductFactory extends Factory { $brands = ['Shimano', 'Venzo', 'Trek', 'Specialized', 'Maxxis', 'Sram', 'Raleigh']; $bikeModels = ['Loki', 'Marlin 5', 'Chisel', 'Talon 3', 'Aspect 950']; - $accessories = ['Cadena 9v', 'Pedales Aluminio', 'Casco MTB', 'Luz Delantera USB', 'Cámara 29"', 'Cubierta Kevlar']; + $accessories = ['Guantes Grip', 'Calco Reflectora', 'Coderas', 'Rodilleras', 'Casco MTB', 'Luz Delantera USB', 'Cubierta Kevlar']; + // PARA DESPUES + $spareParts = ['Manubrio', 'Pedales Aluminio', 'Cámara 29"', 'Rayos x50', 'Disco de Freno', 'Cable de Freno', 'Asiento Goma', 'Cadena 9v']; $type = $this->faker->randomElement(['bike', 'accessory', 'service']); diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 3cb42e7..fe2ec6e 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -52,7 +52,7 @@ class DatabaseSeeder extends Seeder ]); // Generar 10 productos aleatorios más - Product::factory(10)->create(); + Product::factory(50)->create(); // Clientes y Turnos $client = Client::create([ From 1cc848fb13f37eaf237079246f909b4d6f419cf3 Mon Sep 17 00:00:00 2001 From: BryamE Date: Mon, 5 Jan 2026 00:10:43 -0300 Subject: [PATCH 26/36] Actualizacion de plantillas de layout --- resources/views/productos/create.blade.php | 81 ++++------------------ resources/views/productos/edit.blade.php | 66 +++++++++++++++++- resources/views/productos/index.blade.php | 47 +------------ resources/views/productos/show.blade.php | 4 +- 4 files changed, 79 insertions(+), 119 deletions(-) diff --git a/resources/views/productos/create.blade.php b/resources/views/productos/create.blade.php index 97aae25..0a333ff 100644 --- a/resources/views/productos/create.blade.php +++ b/resources/views/productos/create.blade.php @@ -1,61 +1,4 @@ -{{-- - -
    -
    - @csrf - - - -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    - - -
    -
    - - -
    -
    -
    -
    - - -
    -
    - - -
    -
    -
    - - - Volver - -
    - -
    - -
    --}} - - + @@ -65,22 +8,22 @@ @csrf -
    +
    -
    +
    -
    +
    -
    +
    -
    +
    Cancelar
    diff --git a/resources/views/productos/edit.blade.php b/resources/views/productos/edit.blade.php index fc58a00..afc80e7 100644 --- a/resources/views/productos/edit.blade.php +++ b/resources/views/productos/edit.blade.php @@ -1,4 +1,4 @@ - +{{-- Lauck - Editar Editar - {{$product->nombre}} @@ -53,4 +53,66 @@
    - \ No newline at end of file + --}} + + + +
    +
    + @csrf + @method('PUT') +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    +
    + + +
    + +
    + + +
    +
    + + +
    + +
    + + +
    +
    + + +
    + Cancelar + +
    +
    +
    +
    \ No newline at end of file diff --git a/resources/views/productos/index.blade.php b/resources/views/productos/index.blade.php index 29bfe4b..1eed7ef 100644 --- a/resources/views/productos/index.blade.php +++ b/resources/views/productos/index.blade.php @@ -1,49 +1,4 @@ -{{-- - Lauck - Home - Productos - Productos - -
    - - Agregar Producto - -
    - - - - - - - - - - - - - - @foreach ($products as $prod) - - - - - - - - - - @endforeach - -
    NombreMarcaModeloRodadoColorTipoPrecio
    - {{ $prod->name }} - {{ $prod->marca }}{{ $prod->modelo }}{{ $prod->rodado }}{{ $prod->color }}{{ $prod->tipo }}{{ $prod->precio }}
    -
    - - {{$products->links()}} -
    - -
    --}} - - + diff --git a/resources/views/productos/show.blade.php b/resources/views/productos/show.blade.php index 5c666b2..32ac6c8 100644 --- a/resources/views/productos/show.blade.php +++ b/resources/views/productos/show.blade.php @@ -1,7 +1,7 @@ - + - +
    From fb37cc20597bc2efe33f6ddc86f000c4654fa1c8 Mon Sep 17 00:00:00 2001 From: BryamE Date: Mon, 5 Jan 2026 01:51:49 -0300 Subject: [PATCH 27/36] Cambios en catalogo y rutas --- resources/views/catalogo.blade.php | 8 ++++---- resources/views/welcome.blade.php | 21 ++++++++++++--------- routes/web.php | 4 +--- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/resources/views/catalogo.blade.php b/resources/views/catalogo.blade.php index 30a4fa7..9ce1432 100644 --- a/resources/views/catalogo.blade.php +++ b/resources/views/catalogo.blade.php @@ -14,8 +14,8 @@ {{ $prod->name }} @else - diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index e69b210..88e088e 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -1,14 +1,17 @@ - -
    - - 85% - Eficiencia Taller -
    -
    -
    -
    + +
    + + + + + + + + + +
    diff --git a/routes/web.php b/routes/web.php index f416a7c..ea79e8f 100644 --- a/routes/web.php +++ b/routes/web.php @@ -24,9 +24,7 @@ Route::post('login', LoginController::class) ->middleware('throttle:5,1') ->name('login.attempt'); -Route::view('dashboard', 'dashboard') -->middleware('auth') -->name('dashboard'); +Route::view('dashboard', 'dashboard')->middleware('auth')->name('dashboard'); Route::post('logout', function(){ Auth::guard('web')->logout(); From ed27d0337390a50657034d85c5d75c49feecbadd Mon Sep 17 00:00:00 2001 From: BryamE Date: Wed, 7 Jan 2026 03:35:59 -0300 Subject: [PATCH 28/36] MUCHOS CAMBIOS (IMPORTANTES) --- app/Http/Controllers/HomeController.php | 16 +- app/Http/Controllers/ProductosController.php | 31 ++++ database/factories/ProductFactory.php | 1 + ...025_12_06_182358_create_products_table.php | 4 +- ..._06_210513_add_image_to_products_table.php | 22 +++ database/seeders/DatabaseSeeder.php | 13 +- .../views/components/ui/carrousel.blade.php | 141 ++++++++++++++++++ resources/views/productos/create.blade.php | 10 +- resources/views/welcome.blade.php | 17 +-- 9 files changed, 236 insertions(+), 19 deletions(-) create mode 100644 database/migrations/2026_01_06_210513_add_image_to_products_table.php create mode 100644 resources/views/components/ui/carrousel.blade.php diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index dbaf3e2..fd970d4 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -3,11 +3,23 @@ namespace App\Http\Controllers; use Illuminate\Http\Request; +use App\Models\Product; class HomeController extends Controller { - public function __invoke() // * Controlador con un unico metodo se usa __invoke + public function __invoke(Request $request) { - return view('welcome'); + // Si tuvieras un campo 'sales_count', podrías usar ->orderByDesc('sales_count') + $destacados = Product::where('type', 'bike') + ->latest() // Las más nuevas + ->take(5) + ->get(); + + // Si no hay bicis, traemos cualquier cosa para que no se rompa + if ($destacados->isEmpty()) { + $destacados = Product::take(5)->get(); + } + + return view('welcome', compact('destacados')); } } diff --git a/app/Http/Controllers/ProductosController.php b/app/Http/Controllers/ProductosController.php index 76fb067..5a06fae 100644 --- a/app/Http/Controllers/ProductosController.php +++ b/app/Http/Controllers/ProductosController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers; use App\Models\Product; use Illuminate\Http\Request; use Illuminate\Validation\Rule; // Necesario para validar unicidad al editar +use Illuminate\Support\Facades\Storage; // <--- IMPORTANTE: Agregar esto arriba class ProductosController extends Controller { @@ -54,6 +55,7 @@ class ProductosController extends Controller 'min_stock_alert' => 'required|integer|min:0', 'type' => 'required|in:bike,accessory,service', // Solo permite estos 3 valores 'serial_number' => 'nullable|string|max:100', + 'image' => 'nullable|image|mimes:jpeg,png,jpg,webp|max:2048', ]); // 2. Si no viene SKU, generamos uno automático (Opcional pero útil) @@ -61,6 +63,17 @@ class ProductosController extends Controller $validated['sku'] = 'GEN-' . strtoupper(uniqid()); } + // 3. Validacion de imagenes + if ($request->hasFile('image')) { + // Guarda el archivo en storage/app/public/products y devuelve la ruta + $path = $request->file('image')->store('products', 'public'); + $validated['image_path'] = $path; + } + + unset($validated['image']); + + // Para no romper la logica del supplier + $validated['suppliers_id'] = 1; // 3. Creamos el producto Product::create($validated); @@ -102,8 +115,26 @@ class ProductosController extends Controller 'min_stock_alert' => 'required|integer|min:0', 'type' => 'required|in:bike,accessory,service', 'serial_number' => 'nullable|string|max:100', + + 'image' => 'nullable|image|mimes:jpeg,png,jpg,webp|max:2048', ]); + // 2. Manejo de imagen al actualizar + if ($request->hasFile('image')) { + // Borrar la imagen anterior + if ($product->image_path) { + Storage::disk('public')->delete($product->image_path); + } + + // Guardar la nueva + $path = $request->file('image')->store('products', 'public'); + $validated['image_path'] = $path; + } + unset($validated['image']); + + // Para no romper la logica del supplier + $validated['suppliers_id'] = 1; + $product->update($validated); return redirect()->route('productos.index') diff --git a/database/factories/ProductFactory.php b/database/factories/ProductFactory.php index 2c53073..2ab688a 100644 --- a/database/factories/ProductFactory.php +++ b/database/factories/ProductFactory.php @@ -48,6 +48,7 @@ class ProductFactory extends Factory 'type' => $type, // Nro de serie si es bicicleta 'serial_number' => $type === 'bike' ? strtoupper($this->faker->bothify('##??##??')) : null, + 'suppliers_id'=> 1 ]; } } diff --git a/database/migrations/2025_12_06_182358_create_products_table.php b/database/migrations/2025_12_06_182358_create_products_table.php index 5b743f7..ea3aba5 100644 --- a/database/migrations/2025_12_06_182358_create_products_table.php +++ b/database/migrations/2025_12_06_182358_create_products_table.php @@ -21,12 +21,12 @@ return new class extends Migration $table->decimal('cost', 10, 2)->nullable(); // Costo (solo admin) $table->integer('stock_quantity')->default(0); - $table->integer('min_stock_alert')->default(5); // Alerta + $table->integer('min_stock_alert'); // Alerta $table->enum('type', ['bike', 'accessory', 'service']); $table->string('serial_number')->nullable(); // Solo para bicis - $table->foreignId('suppliers_id')->constrained(); + $table->foreignId('suppliers_id')->constrained()->default(1); $table->timestamps(); }); } diff --git a/database/migrations/2026_01_06_210513_add_image_to_products_table.php b/database/migrations/2026_01_06_210513_add_image_to_products_table.php new file mode 100644 index 0000000..addaf25 --- /dev/null +++ b/database/migrations/2026_01_06_210513_add_image_to_products_table.php @@ -0,0 +1,22 @@ +string('image_path')->nullable()->after('type'); + }); + } + + public function down(): void + { + Schema::table('products', function (Blueprint $table) { + $table->dropColumn('image_path'); + }); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index fe2ec6e..925158c 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -6,6 +6,7 @@ use Illuminate\Database\Seeder; use App\Models\User; use App\Models\Product; use App\Models\Client; +use App\Models\Supplier; use App\Models\Appointment; // use Illuminate\Database\Console\Seeds\WithoutModelEvents; @@ -29,6 +30,12 @@ class DatabaseSeeder extends Seeder 'role' => 'employee', ]); + Supplier::create([ + 'name' => 'Cámara 29 Válvula Auto', + 'phone' => '3434567890', + 'email' => 'suplier@suplier.com' + ]); + //Crear Productos Product::create([ 'name' => 'Cámara 29 Válvula Auto', @@ -37,7 +44,8 @@ class DatabaseSeeder extends Seeder 'cost' => 2500, 'stock_quantity' => 20, 'min_stock_alert' => 5, - 'type' => 'accessory' + 'type' => 'accessory', + 'suppliers_id' => 1 ]); Product::create([ @@ -48,7 +56,8 @@ class DatabaseSeeder extends Seeder 'stock_quantity' => 2, 'min_stock_alert' => 1, 'type' => 'bike', - 'serial_number' => 'VZ998877' + 'serial_number' => 'VZ998877', + 'suppliers_id' => 1 ]); // Generar 10 productos aleatorios más diff --git a/resources/views/components/ui/carrousel.blade.php b/resources/views/components/ui/carrousel.blade.php new file mode 100644 index 0000000..5f1e1a8 --- /dev/null +++ b/resources/views/components/ui/carrousel.blade.php @@ -0,0 +1,141 @@ +@props(['items']) + + + + \ No newline at end of file diff --git a/resources/views/productos/create.blade.php b/resources/views/productos/create.blade.php index 0a333ff..02f9d6b 100644 --- a/resources/views/productos/create.blade.php +++ b/resources/views/productos/create.blade.php @@ -4,7 +4,7 @@
    -
    + @csrf @@ -59,6 +59,14 @@
    + +
    + + + {{-- @error('image') {{ $message }} @enderror --}} +
    diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index 88e088e..e8d5dc3 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -1,17 +1,10 @@ - -
    - - - - - - - - - - + +
    + +
    + From 37e8f498be0dabfa18fda6926bde9ab7ca36fa32 Mon Sep 17 00:00:00 2001 From: BryamE Date: Wed, 7 Jan 2026 17:26:16 -0300 Subject: [PATCH 29/36] Creacion de index de ventas y mejora de vistas de catalogo, productos, y mejoras de ruteo a diferentes paginas, entre otros. --- app/Http/Controllers/ProductosController.php | 19 ++++ app/Http/Controllers/SaleController.php | 12 ++- resources/views/catalogo.blade.php | 8 +- resources/views/components/navbar.blade.php | 9 +- resources/views/dashboard.blade.php | 2 +- resources/views/productos/index.blade.php | 22 +++-- resources/views/productos/show.blade.php | 12 +-- resources/views/sales/index.blade.php | 96 +++++++++++++++++--- routes/web.php | 10 +- 9 files changed, 156 insertions(+), 34 deletions(-) diff --git a/app/Http/Controllers/ProductosController.php b/app/Http/Controllers/ProductosController.php index 5a06fae..7ba1847 100644 --- a/app/Http/Controllers/ProductosController.php +++ b/app/Http/Controllers/ProductosController.php @@ -16,6 +16,7 @@ class ProductosController extends Controller { // Recuperamos lo que el usuario escribió en el buscador (si escribió algo) $query = $request->input('search'); + $status = $request->input('stock_status'); // Construimos la consulta $products = Product::query() @@ -24,6 +25,24 @@ class ProductosController extends Controller return $q->where('name', 'like', "%{$query}%") ->orWhere('sku', 'like', "%{$query}%"); }) + ->when($status, function ($q) use ($status) { + if ($status === 'low') { + // Rojo: Menor o igual a la alerta + return $q->whereColumn('stock_quantity', '<', 'min_stock_alert') + ->where('type', '!=', 'service'); // Ignoramos servicios + } + elseif ($status === 'medium') { + // Amarillo: Mayor a alerta PERO menor o igual a alerta + 2 (margen pequeño) + return $q->whereColumn('stock_quantity', '>=', 'min_stock_alert') + ->whereRaw('stock_quantity <= (min_stock_alert + 1)') // Ajusta este "+ 5" según tu criterio de "amarillo" + ->where('type', '!=', 'service'); + } + elseif ($status === 'ok') { + // Verde: Stock saludable + return $q->whereRaw('stock_quantity > (min_stock_alert + 1)') + ->where('type', '!=', 'service'); + } + }) ->orderBy('stock_quantity', 'asc') // Ordenamos primero los que tienen poco stock (Alerta visual) ->paginate(10) // Paginamos de a 10 ->withQueryString(); // Mantiene el filtro de búsqueda al cambiar de página diff --git a/app/Http/Controllers/SaleController.php b/app/Http/Controllers/SaleController.php index 8e8a7f7..c7e0f79 100644 --- a/app/Http/Controllers/SaleController.php +++ b/app/Http/Controllers/SaleController.php @@ -7,17 +7,25 @@ use App\Models\Product; use App\Models\Sale; use App\Models\SaleDetail; use Illuminate\Support\Facades\DB; -// use App\Models\Client; class SaleController extends Controller { + public function index() + { + $sales = Sale::with('client') + ->orderBy('created_at', 'desc') + ->paginate(15); + + return view('sales.index', compact('sales')); + } + public function create() { // Buscamos productos que tengan stock mayor a 0 para mostrar en el selector $products = Product::where('stock_quantity', '>', 0)->get(); - $clients = \App\Models\Client::orderBy('name')->get(); + $clients = Client::orderBy('name')->get(); return view('sales.create', compact('products', 'clients')); } diff --git a/resources/views/catalogo.blade.php b/resources/views/catalogo.blade.php index 9ce1432..0d33c3b 100644 --- a/resources/views/catalogo.blade.php +++ b/resources/views/catalogo.blade.php @@ -10,8 +10,8 @@ @foreach ($products as $prod)
    {{-- Imagen si existe --}} - @if (!empty($prod->img)) - {{ $prod->name }}image_path)) + {{ $prod->name }} @else
    @@ -46,5 +46,9 @@ @else

    No hay productos disponibles.

    @endif + +
    + {{ $products->links() }} +
    diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index 61a108a..5bc8c95 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -2,7 +2,12 @@
  • - Ventas diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index 4be0926..7063627 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -4,7 +4,7 @@ diff --git a/resources/views/productos/index.blade.php b/resources/views/productos/index.blade.php index 1eed7ef..bd97bde 100644 --- a/resources/views/productos/index.blade.php +++ b/resources/views/productos/index.blade.php @@ -9,8 +9,8 @@
    - -
    + +
    + +
    + +
    + @@ -27,7 +38,6 @@ + Nuevo Producto
    -
    @@ -58,8 +68,10 @@
    @if($product->type === 'service') - - @elseif($product->stock_quantity <= $product->min_stock_alert) + @elseif($product->stock_quantity < $product->min_stock_alert) {{ $product->stock_quantity }} + @elseif($product->stock_quantity <= $product->min_stock_alert+1) + {{ $product->stock_quantity }} @else {{ $product->stock_quantity }} @endif @@ -78,10 +90,8 @@
    -
    {{ $products->links() }}
    - \ No newline at end of file diff --git a/resources/views/productos/show.blade.php b/resources/views/productos/show.blade.php index 32ac6c8..2ed4516 100644 --- a/resources/views/productos/show.blade.php +++ b/resources/views/productos/show.blade.php @@ -10,27 +10,27 @@
    {{$product->name}}
    -
    Modelo
    +
    SKU
    {{$product->sku}}
    -
    Color
    +
    Descripcion
    {{$product->description}}
    -
    Rodado
    +
    Costo
    {{$product->cost}}
    -
    Tipo
    +
    Precio
    {{$product->price}}
    -
    Descripcion
    +
    Cantidad en Stock
    {{$product->stock_quantity}}
    -
    Precio
    +
    Tipo
    {{$product->type}}
    diff --git a/resources/views/sales/index.blade.php b/resources/views/sales/index.blade.php index 8174db7..a19df33 100644 --- a/resources/views/sales/index.blade.php +++ b/resources/views/sales/index.blade.php @@ -1,12 +1,84 @@ - - - - - - - Document - - -

    Gwssssssssssssssss

    - - \ No newline at end of file + + + + + +
    + +
    + +
    + + + + + Registrar Venta + +
    + + +
    + + + + + + + + + + + + + @forelse($sales as $sale) + + + + + + + + + @empty + + + + @endforelse + +
    # RefFechaClienteMétodo PagoTotalAcciones
    + #{{ str_pad($sale->id, 5, '0', STR_PAD_LEFT) }} + +
    {{ $sale->created_at->format('d/m/Y') }}
    +
    {{ $sale->created_at->format('H:i') }} hs
    +
    + @if($sale->client) +
    {{ $sale->client->name }}
    +
    Cli. Registrado
    + @else + Consumidor Final + @endif +
    + + {{ $sale->payment_method }} + + + ${{ number_format($sale->total, 2, ',', '.') }} + + +
    +
    + +

    No hay ventas registradas aún.

    +

    Realiza tu primera venta desde el botón verde.

    +
    +
    +
    + + +
    + {{ $sales->links() }} +
    + +
    \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index ea79e8f..50590bc 100644 --- a/routes/web.php +++ b/routes/web.php @@ -45,9 +45,13 @@ Route::middleware(['auth'])->group(function () { Route::resource('clients', ClientController::class); Route::get('/checker', [ProductosController::class, 'checker'])->name('productos.checker'); - //Route::get('/sales', [SaleController::class, 'index'])->name('sales.index'); - Route::get('/sales/create', [SaleController::class, 'create'])->name('sales.create'); - Route::get('/sales/store', [SaleController::class, 'store'])->name('sales.store'); + Route::controller(SaleController::class)->prefix('sales')->name('sales.')->group(function () { + Route::get('/', 'index')->name('index'); // Historial (Nueva) + Route::get('/create', 'create')->name('create'); // Formulario (Existente) + Route::post('/', 'store')->name('store'); // Guardar (CORREGIDO a POST) + Route::get('/{sale}', 'show')->name('show'); // Ver detalle de una venta (Opcional futura) + }); + }); From 8f10e3595d2c512cff4539c61269b4997939aa7b Mon Sep 17 00:00:00 2001 From: BryamE Date: Thu, 8 Jan 2026 04:23:06 -0300 Subject: [PATCH 30/36] FUNCIONA VENTAS (quedo horrible la vista, despues la cambio, pero anda!) --- app/Http/Controllers/ClientController.php | 2 +- app/Http/Controllers/ProductosController.php | 17 - app/Http/Controllers/SaleController.php | 4 +- app/Models/Sale.php | 10 +- resources/views/clients/create.blade.php | 6 +- resources/views/components/layout.blade.php | 2 + resources/views/productos/checker.blade.php | 0 resources/views/sales/create.blade.php | 447 ++++++++++--------- routes/web.php | 11 +- 9 files changed, 263 insertions(+), 236 deletions(-) delete mode 100644 resources/views/productos/checker.blade.php diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index fcf5db8..c165d18 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -19,7 +19,7 @@ class ClientController extends Controller */ public function create() { - // + return view('clients.create'); } /** diff --git a/app/Http/Controllers/ProductosController.php b/app/Http/Controllers/ProductosController.php index 7ba1847..92e1c74 100644 --- a/app/Http/Controllers/ProductosController.php +++ b/app/Http/Controllers/ProductosController.php @@ -169,21 +169,4 @@ class ProductosController extends Controller return redirect()->route('productos.index') ->with('success', 'Producto eliminado.'); } - - /** - * Vista simplificada para consultar precios (empleados). - */ - public function checker(Request $request) - { - $search = $request->input('query'); - $result = null; - - if ($search) { - $result = Product::where('sku', $search) - ->orWhere('name', 'like', "%{$search}%") - ->first(); // Devuelve el primer resultado encontrado - } - - return view('productos.checker', compact('result', 'search')); - } } \ No newline at end of file diff --git a/app/Http/Controllers/SaleController.php b/app/Http/Controllers/SaleController.php index c7e0f79..6b3600e 100644 --- a/app/Http/Controllers/SaleController.php +++ b/app/Http/Controllers/SaleController.php @@ -46,10 +46,10 @@ class SaleController extends Controller foreach ($request->items as $item) { $product = Product::find($item['product_id']); - $totalSale += $product->precio * $item['quantity']; + $totalSale += $product->price * $item['quantity']; if ($product->stock_quantity < $item['quantity']) { - throw new \Exception("No hay suficiente stock de " . $product->nombre); + throw new \Exception("No hay suficiente stock de " . $product->name); } } diff --git a/app/Models/Sale.php b/app/Models/Sale.php index aeeca90..67f7dcb 100644 --- a/app/Models/Sale.php +++ b/app/Models/Sale.php @@ -11,13 +11,19 @@ class Sale extends Model // Permitimos asignación masiva para poder guardar rápido protected $guarded = []; - // Relación 1: Una venta pertenece a un Cliente (User) + // Relación 1: Una venta la realiza un Usuario (User) public function user() { return $this->belongsTo(User::class); } - // Relación 2: Una venta tiene muchos items o detalles + // Relación 2: Una venta pertenece a un Cliente (User) + public function client() + { + return $this->belongsTo(Client::class); + } + + // Relación 3: Una venta tiene muchos items o detalles public function details() { return $this->hasMany(SaleDetail::class); diff --git a/resources/views/clients/create.blade.php b/resources/views/clients/create.blade.php index 6265ad0..0fe014d 100644 --- a/resources/views/clients/create.blade.php +++ b/resources/views/clients/create.blade.php @@ -1,5 +1,3 @@ -@extends('layouts.app') -@section('main') +

    formulario de crear cliente

    - -@endsection \ No newline at end of file +
    \ No newline at end of file diff --git a/resources/views/components/layout.blade.php b/resources/views/components/layout.blade.php index 7f5147b..b6f852c 100644 --- a/resources/views/components/layout.blade.php +++ b/resources/views/components/layout.blade.php @@ -35,5 +35,7 @@ btn.addEventListener('click', () => menu.classList.toggle('hidden')); } + @stack('scripts') + \ No newline at end of file diff --git a/resources/views/productos/checker.blade.php b/resources/views/productos/checker.blade.php deleted file mode 100644 index e69de29..0000000 diff --git a/resources/views/sales/create.blade.php b/resources/views/sales/create.blade.php index 26ec74a..864c739 100644 --- a/resources/views/sales/create.blade.php +++ b/resources/views/sales/create.blade.php @@ -1,223 +1,262 @@ - -
    -
    + + + + + + + +
    + @csrf + +
    -
    -
    -

    Nueva Venta en Mostrador

    -
    - - @if (session('success')) -
    - ¡Éxito! {{ session('success') }} -
    - @endif - - @if (session('error')) -
    - Error: {{ session('error') }} -
    - @endif - - @if ($errors->any()) -
    -
      - @foreach ($errors->all() as $error) -
    • • {{ $error }}
    • - @endforeach -
    -
    - @endif - - - - - @csrf - -
    - -
    - + @foreach($clients as $client) - + @endforeach - - - + -
    -
    - -
    -
    -
    - - -
    - -
    - - -
    - -
    - $0.00 -
    - -
    - -
    -
    -
    - -
    - -
    - -
    -
    - Total a Pagar: $0.00 -
    -
    - -
    +
    - -
    - - +
    +
    + + +
    +
    + +
    +

    2. Detalle de Venta

    + +
    + + +
    + + + + + + + + + + + + + +
    ProductoCant.PrecioSubtotal
    + + +
    +

    El carrito está vacío

    +

    Presiona "Agregar Producto" para comenzar

    +
    +
    + + +
    +
    + Total a Pagar + $0.00 +
    + +
    + Cancelar +
    - + +
    -
    + + + + @push('scripts') + {{-- SCRIPTS --}} + + @endpush - -@push('scripts') - -@endpush \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 50590bc..5fc113e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -39,17 +39,16 @@ Route::view('register', 'register')->name('register'); Route::post('register', RegisterController::class)->name('register.store'); Route::middleware(['auth'])->group(function () { + Route::resource('clients', ClientController::class); Route::resource('productos', ProductosController::class)->parameters([ 'productos' => 'product' ]); - Route::resource('clients', ClientController::class); - Route::get('/checker', [ProductosController::class, 'checker'])->name('productos.checker'); Route::controller(SaleController::class)->prefix('sales')->name('sales.')->group(function () { - Route::get('/', 'index')->name('index'); // Historial (Nueva) - Route::get('/create', 'create')->name('create'); // Formulario (Existente) - Route::post('/', 'store')->name('store'); // Guardar (CORREGIDO a POST) - Route::get('/{sale}', 'show')->name('show'); // Ver detalle de una venta (Opcional futura) + Route::get('/', 'index')->name('index'); + Route::get('/create', 'create')->name('create'); + Route::post('/', 'store')->name('store'); + Route::get('/{sale}', 'show')->name('show'); }); }); From dc400e010213e006f511265330413c6c77639f99 Mon Sep 17 00:00:00 2001 From: gianella Date: Thu, 8 Jan 2026 19:41:21 -0300 Subject: [PATCH 31/36] creo que pude instalar select2, create sales y crud client o casi crud --- app/Http/Controllers/ClientController.php | 81 +++- app/Http/Controllers/SaleController.php | 61 ++- package-lock.json | 9 +- package.json | 3 +- resources/js/app.js | 12 + resources/views/clients/create.blade.php | 52 ++- resources/views/clients/edit.blade.php | 79 ++++ resources/views/clients/index.blade.php | 105 +++++ resources/views/dashboard.blade.php | 2 +- resources/views/sales/create.blade.php | 460 +++++++++++++--------- routes/web.php | 2 +- 11 files changed, 612 insertions(+), 254 deletions(-) create mode 100644 resources/views/clients/edit.blade.php create mode 100644 resources/views/clients/index.blade.php diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index fcf5db8..b456d43 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -3,15 +3,28 @@ namespace App\Http\Controllers; use Illuminate\Http\Request; +use App\Models\Client; class ClientController extends Controller { /** * Display a listing of the resource. */ - public function index() + public function index(Request $request) { - // + $query = $request->input('search'); + + $clients = Client::query() + ->when($query, function ($q) use ($query) { + // Si hay búsqueda, filtra por nombre o SKU + return $q->where('name', 'like', "%{$query}%"); + }) + ->orderBy('name', 'asc') + //->orderBy('create_at', 'asc') + ->paginate(10) // Paginamos de a 10 + ->withQueryString(); // Mantiene el filtro de búsqueda al cambiar de página + + return view('clients.index', compact('clients')); } /** @@ -19,7 +32,7 @@ class ClientController extends Controller */ public function create() { - // + return view('clients.create'); } /** @@ -27,7 +40,28 @@ class ClientController extends Controller */ public function store(Request $request) { - // + $validated = $request->validate([ + 'name' => 'required|string|max:255', + 'phone' => 'nullable|string|max:50', + 'email' => 'nullable|email|max:255|unique:clients,email', + 'address' => 'nullable|string|max:255', + ]); + + // 1. Guardamos el cliente en una variable para tener su ID + $client = Client::create($validated); + + // 2. Verificamos el origen + if ($request->input('origin') === 'sales') { + + // Si vino de ventas, volvemos a ventas + // Y pasamos el ID del nuevo cliente para auto-seleccionarlo + return redirect()->route('sales.create', ['new_client_id' => $client->id]) + ->with('success', 'Cliente creado. Ya puedes seleccionarlo.'); + } + + // 3. Si no, comportamiento normal (volver al index de clientes) + return redirect()->route('clients.index') + ->with('success', 'Cliente creado correctamente.'); } /** @@ -38,27 +72,38 @@ class ClientController extends Controller // } - /** - * Show the form for editing the specified resource. - */ - public function edit(string $id) + public function edit(Client $client) { - // + // Reutilizamos la vista de create, o creamos una edit.blade.php similar + return view('clients.edit', compact('client')); + } + + public function update(Request $request, Client $client) + { + $validated = $request->validate([ + 'name' => 'required|string|max:255', + 'phone' => 'nullable|string|max:50', + 'email' => 'nullable|email|max:255|unique:clients,email,' . $client->id, // Ignorar email propio + 'address' => 'nullable|string|max:255', + ]); + + $client->update($validated); + + return redirect()->route('clients.index')->with('success', 'Cliente actualizado correctamente.'); } - /** - * Update the specified resource in storage. - */ - public function update(Request $request, string $id) - { - // - } /** * Remove the specified resource from storage. */ - public function destroy(string $id) + public function destroy(Client $client) { - // + try { + $client->delete(); + return redirect()->route('clients.index')->with('success', 'Cliente eliminado correctamente.'); + } catch (\Illuminate\Database\QueryException $e) { + + return back()->with('error', 'No se puede eliminar el cliente porque tiene ventas registradas.'); + } } } diff --git a/app/Http/Controllers/SaleController.php b/app/Http/Controllers/SaleController.php index 8e8a7f7..b7f3832 100644 --- a/app/Http/Controllers/SaleController.php +++ b/app/Http/Controllers/SaleController.php @@ -3,78 +3,77 @@ namespace App\Http\Controllers; use Illuminate\Http\Request; -use App\Models\Product; +use App\Models\Product; +use App\Models\Client; use App\Models\Sale; use App\Models\SaleDetail; use Illuminate\Support\Facades\DB; -// -use App\Models\Client; class SaleController extends Controller { public function create() { - // Buscamos productos que tengan stock mayor a 0 para mostrar en el selector + // Traemos productos con stock y clientes para los selectores $products = Product::where('stock_quantity', '>', 0)->get(); - - $clients = \App\Models\Client::orderBy('name')->get(); + $clients = Client::orderBy('name')->get(); return view('sales.create', compact('products', 'clients')); } public function store(Request $request) { + // Validación estricta $request->validate([ + 'client_id' => 'nullable|exists:clients,id', 'payment_method' => 'required|string', - 'client_id' => 'nullable|exists:clients,id', - 'items' => 'required|array', + 'items' => 'required|array', 'items.*.product_id' => 'required|exists:products,id', - 'items.*.quantity' => 'required|integer|min:1', + 'items.*.quantity' => 'required|integer|min:1', ]); try { DB::transaction(function () use ($request) { - $totalSale = 0; + + $totalVenta = 0; - foreach ($request->items as $item) { - $product = Product::find($item['product_id']); - $totalSale += $product->precio * $item['quantity']; + // 1. Calcular total previo (Solo habrá 1 item por ahora, pero el bucle sirve igual) + foreach ($request->items as $itemData) { + $product = Product::findOrFail($itemData['product_id']); - if ($product->stock_quantity < $item['quantity']) { - throw new \Exception("No hay suficiente stock de " . $product->nombre); + if ($product->stock_quantity < $itemData['quantity']) { + throw new \Exception("Stock insuficiente para: " . $product->name); } + + $totalVenta += $product->price * $itemData['quantity']; } - //cabecera + // 2. Crear Venta $sale = Sale::create([ - //'user_id' => auth()->id(), //empleado logueado - 'client_id' => $request->client_id, - 'total' => $totalSale, + 'client_id' => $request->client_id, + 'total' => $totalVenta, 'payment_method' => $request->payment_method, + // 'user_id' => auth()->id(), // Descomenta si usas autenticación ]); - foreach ($request->items as $item) { - $product = Product::find($item['product_id']); + // 3. Guardar Detalle y Restar Stock + foreach ($request->items as $itemData) { + $product = Product::findOrFail($itemData['product_id']); SaleDetail::create([ - 'sale_id' => $sale->id, + 'sale_id' => $sale->id, 'product_id' => $product->id, - 'quantity' => $item['quantity'], - 'price' => $product->price, + 'quantity' => $itemData['quantity'], + 'price' => $product->price, ]); - $nuevoStock = $product->stock_quantity - $item['quantity']; - $product->stock_quantity = $nuevoStock; - $product->save(); + + $product->decrement('stock_quantity', $itemData['quantity']); } }); - // 5. REDIRECCIÓN DE ÉXITO - // Redirigimos al usuario con un mensaje flash [cite: 668] return redirect()->route('sales.create')->with('success', '¡Venta registrada correctamente!'); } catch (\Exception $e) { - // Si algo falló (ej: falta stock), volvemos atrás con el error - return back()->with('error', 'Error en la venta: ' . $e->getMessage()); + return back()->with('error', $e->getMessage())->withInput(); } } } diff --git a/package-lock.json b/package-lock.json index 1f1aba3..278d680 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,8 @@ "": { "dependencies": { "@tailwindcss/postcss": "^4.1.18", - "jquery": "^3.7.1" + "jquery": "^3.7.1", + "select2": "^4.1.0-rc.0" }, "devDependencies": { "@tailwindcss/vite": "^4.1.18", @@ -2243,6 +2244,12 @@ "tslib": "^2.1.0" } }, + "node_modules/select2": { + "version": "4.1.0-rc.0", + "resolved": "https://registry.npmjs.org/select2/-/select2-4.1.0-rc.0.tgz", + "integrity": "sha512-Hr9TdhyHCZUtwznEH2CBf7967mEM0idtJ5nMtjvk3Up5tPukOLXbHUNmh10oRfeNIhj+3GD3niu+g6sVK+gK0A==", + "license": "MIT" + }, "node_modules/shell-quote": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", diff --git a/package.json b/package.json index 385e02e..259ef1c 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "dependencies": { "@tailwindcss/postcss": "^4.1.18", - "jquery": "^3.7.1" + "jquery": "^3.7.1", + "select2": "^4.1.0-rc.0" } } diff --git a/resources/js/app.js b/resources/js/app.js index e59d6a0..d0ead51 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -1 +1,13 @@ import './bootstrap'; +// 1. Importar jQuery +import jQuery from 'jquery'; + +// 2. Hacerlo global (IMPORTANTE para que funcione $(document).ready en Blade) +window.$ = window.jQuery = jQuery; + +// 3. Importar Select2 +import select2 from 'select2'; +select2(); // Inicializar el plugin + +// 4. Importar los estilos de Select2 (Opcional aquí, o en CSS) +import 'select2/dist/css/select2.css'; diff --git a/resources/views/clients/create.blade.php b/resources/views/clients/create.blade.php index 6265ad0..5bddb0b 100644 --- a/resources/views/clients/create.blade.php +++ b/resources/views/clients/create.blade.php @@ -1,5 +1,49 @@ -@extends('layouts.app') -@section('main') -

    formulario de crear cliente

    + -@endsection \ No newline at end of file + + +
    + +
    + @csrf + + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + + @error('address') + {{ $message }} + @enderror +
    + +
    + +
    + Cancelar + + +
    + +
    +
    +
    \ No newline at end of file diff --git a/resources/views/clients/edit.blade.php b/resources/views/clients/edit.blade.php new file mode 100644 index 0000000..bb10afb --- /dev/null +++ b/resources/views/clients/edit.blade.php @@ -0,0 +1,79 @@ + + + + +
    + +
    + @csrf + @method('PUT')
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + + + @error('address') + {{ $message }} + @enderror +
    + +
    + +
    + + + Cancelar + + + +
    + +
    +
    +
    \ No newline at end of file diff --git a/resources/views/clients/index.blade.php b/resources/views/clients/index.blade.php new file mode 100644 index 0000000..d2853b0 --- /dev/null +++ b/resources/views/clients/index.blade.php @@ -0,0 +1,105 @@ + + + + + @if(session('success')) +
    + {{ session('success') }} +
    + @endif + +
    + +
    +
    +
    + +
    + +
    +
    + + + + Nuevo Cliente + +
    + +
    + + + + + + + + + + + @forelse($clients as $client) + + + + + + + + + + + + @empty + + + + @endforelse + +
    Cliente / EmailTeléfono / WhatsAppDirecciónAcciones
    +
    {{ $client->name }}
    +
    + {{ $client->email ?? 'Sin email registrado' }} +
    +
    + @if($client->phone) +
    + {{ $client->phone }} + WA +
    + @else + No registrado + @endif +
    + + {{ $client->address ?? '-' }} + + + + Editar + + +
    + @csrf + @method('DELETE') + + +
    +
    +
    + + + +

    No se encontraron clientes.

    +
    +
    +
    + +
    + {{ $clients->links() }} +
    + +
    \ No newline at end of file diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index 4be0926..a085c3a 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -21,7 +21,7 @@ - + diff --git a/resources/views/sales/create.blade.php b/resources/views/sales/create.blade.php index 26ec74a..5dc5ace 100644 --- a/resources/views/sales/create.blade.php +++ b/resources/views/sales/create.blade.php @@ -1,223 +1,289 @@ - -
    -
    - -
    -
    -

    Nueva Venta en Mostrador

    -
    - - @if (session('success')) -
    - ¡Éxito! {{ session('success') }} -
    - @endif - - @if (session('error')) -
    - Error: {{ session('error') }} -
    - @endif - - @if ($errors->any()) -
    -
      - @foreach ($errors->all() as $error) -
    • • {{ $error }}
    • + + @push('styles') + + @endpush + + + +
      + + @if(session('success')) +
      + {{ session('success') }} +
      + @endif + @if(session('error')) +
      + {{ session('error') }} +
      + @endif + @if($errors->any()) +
      +
        + @foreach($errors->all() as $error) +
      • {{ $error }}
      • + @endforeach +
      +
      + @endif + +
      + @csrf + +
      +
      + +
      +
      - @endif - - - - - @csrf - -
      - -
      - + + @foreach($products as $product) + @endforeach - - - + -
      -
      - -
      -
      -
      - - -
      - -
      - - -
      - -
      - $0.00 -
      - -
      - -
      + +
      + +
      -
      - -
      - -
      - -
      -
      - Total a Pagar: $0.00 + +
      + Subtotal + $0.00
      -
      - -
      -
      - - -
      - -
      - - Cancelar - -
      - +
      + +
      + +
      + +
      +
      + Monto Total a Pagar + $0.00 +
      +
      -
      + +
      + +
      + + +
      + +
      + + Cancelar + + +
      +
      + +
      - -@push('scripts') - -@endpush \ No newline at end of file + function calcularFila(row) { + let select = row.find('.product-select'); + let input = row.find('.quantity-input'); + let option = select.find(':selected'); + let price = parseFloat(option.data('price')) || 0; + let qty = parseInt(input.val()) || 0; + let subtotal = price * qty; + row.find('.row-total').text('$' + subtotal.toFixed(2)); + } + + function recalcularTodo() { + let grandTotal = 0; + $('.item-row').each(function() { + let row = $(this); + let price = parseFloat(row.find('.product-select').find(':selected').data('price')) || 0; + let qty = parseInt(row.find('.quantity-input').val()) || 0; + grandTotal += (price * qty); + }); + $('#grand-total').text('$' + grandTotal.toFixed(2)); + } + + function actualizarContadorItems() { + $('#item-count').text($('.item-row').length); + } + + function actualizarBloqueos() { + let seleccionados = []; + $('.product-select').each(function() { + let valor = $(this).val(); + if (valor) seleccionados.push(valor); + }); + + $('.product-select').each(function() { + let selectActual = $(this); + let miValor = selectActual.val(); + selectActual.find('option').each(function() { + let opcion = $(this); + let valorOpcion = opcion.val(); + if (!valorOpcion) return; + + if (seleccionados.includes(valorOpcion) && valorOpcion != miValor) { + opcion.prop('disabled', true); + } else { + opcion.prop('disabled', false); + } + }); + }); + } + + \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index ea79e8f..0e86915 100644 --- a/routes/web.php +++ b/routes/web.php @@ -47,7 +47,7 @@ Route::middleware(['auth'])->group(function () { //Route::get('/sales', [SaleController::class, 'index'])->name('sales.index'); Route::get('/sales/create', [SaleController::class, 'create'])->name('sales.create'); - Route::get('/sales/store', [SaleController::class, 'store'])->name('sales.store'); + Route::post('/sales/store', [SaleController::class, 'store'])->name('sales.store'); }); From 82d86c8264fa701a37ebce6ad60ca9cb89ecbd44 Mon Sep 17 00:00:00 2001 From: gianella Date: Thu, 8 Jan 2026 19:49:42 -0300 Subject: [PATCH 32/36] arreglito --- resources/views/clients/create.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/clients/create.blade.php b/resources/views/clients/create.blade.php index 5bddb0b..34bacb0 100644 --- a/resources/views/clients/create.blade.php +++ b/resources/views/clients/create.blade.php @@ -37,7 +37,7 @@
      - Cancelar + Cancelar + Ver Detalle @empty diff --git a/resources/views/sales/show.blade.php b/resources/views/sales/show.blade.php new file mode 100644 index 0000000..9271fa9 --- /dev/null +++ b/resources/views/sales/show.blade.php @@ -0,0 +1,149 @@ + + + + + + +
      + + + Volver al Historial + + + +
      + + +
      + + +
      +
      + +
      +
      + +
      + + CICLES LAUCK + +
      +

      + Av. Francisco Ramírez 1389
      + Paraná, Entre Ríos
      + Tel: 343 422-0103 +

      +
      + +
      +

      Comprobante de Venta

      +
      #{{ str_pad($sale->id, 5, '0', STR_PAD_LEFT) }}
      +
      + Fecha: {{ $sale->created_at->format('d/m/Y') }}
      + Hora: {{ $sale->created_at->format('H:i') }} hs +
      +
      +
      + + +
      +
      +

      Facturado A:

      + @if($sale->client) +

      {{ $sale->client->name }}

      +

      {{ $sale->client->phone }}

      +

      {{ $sale->client->email }}

      + @if($sale->client->address) +

      {{ $sale->client->address }}

      + @endif + @else +

      Consumidor Final

      +

      Venta anónima de mostrador

      + @endif +
      + +
      +

      Método de Pago:

      + + {{ $sale->payment_method }} + +
      +
      + + +
      + + + + + + + + + + + @foreach($sale->details as $detail) + + + + + + + @endforeach + + + + + + + +
      ProductoPrecio Unit.Cant.Subtotal
      +
      {{ $detail->product->name }}
      +
      {{ $detail->product->sku }}
      +
      + ${{ number_format($detail->price, 2, ',', '.') }} + + {{ $detail->quantity }} + + ${{ number_format($detail->price * $detail->quantity, 2, ',', '.') }} +
      Total a Pagar + ${{ number_format($sale->total, 2, ',', '.') }} +
      +
      + + +
      +

      ¡Gracias por tu compra!

      +

      Documento no valido como factura.

      +
      + +
      + + + + +
      \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 5fc113e..74304f5 100644 --- a/routes/web.php +++ b/routes/web.php @@ -43,13 +43,7 @@ Route::middleware(['auth'])->group(function () { Route::resource('productos', ProductosController::class)->parameters([ 'productos' => 'product' ]); - - Route::controller(SaleController::class)->prefix('sales')->name('sales.')->group(function () { - Route::get('/', 'index')->name('index'); - Route::get('/create', 'create')->name('create'); - Route::post('/', 'store')->name('store'); - Route::get('/{sale}', 'show')->name('show'); - }); + Route::resource('sales', SaleController::class)->only(['index', 'create', 'store', 'show']); }); From 5adea8351794db696a48618dcf55cdc37930af8f Mon Sep 17 00:00:00 2001 From: BryamE Date: Thu, 8 Jan 2026 21:18:15 -0300 Subject: [PATCH 34/36] Coso --- resources/views/sales/index.blade.php | 42 +-------------------------- 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/resources/views/sales/index.blade.php b/resources/views/sales/index.blade.php index 99e0e22..faee08e 100644 --- a/resources/views/sales/index.blade.php +++ b/resources/views/sales/index.blade.php @@ -30,53 +30,13 @@ - @forelse($sales as $sale) - - - #{{ str_pad($sale->id, 5, '0', STR_PAD_LEFT) }} - - -
      {{ $sale->created_at->format('d/m/Y') }}
      -
      {{ $sale->created_at->format('H:i') }} hs
      - - - @if($sale->client) -
      {{ $sale->client->name }}
      -
      Cli. Registrado
      - @else - Consumidor Final - @endif - - - - {{ $sale->payment_method }} - - - - ${{ number_format($sale->total, 2, ',', '.') }} - - - Ver Detalle - - - @empty - - -
      - -

      No hay ventas registradas aún.

      -

      Realiza tu primera venta desde el botón verde.

      -
      - - - @endforelse +
      - {{ $sales->links() }}
      \ No newline at end of file From 59d5cf748d51c7853b7f9876fc0cf9077c3ea4af Mon Sep 17 00:00:00 2001 From: BryamE Date: Fri, 9 Jan 2026 01:34:26 -0300 Subject: [PATCH 35/36] Cambios en vista de visitante, separada logica de productos y catalogos poara manejo individual, creados catalogo.index y catalogo.show. acomodadas rutas del catalogo para evitar errores. --- app/Http/Controllers/CatalogoController.php | 9 +- .../index.blade.php} | 18 +-- resources/views/catalogo/show.blade.php | 105 ++++++++++++++++++ resources/views/components/navbar.blade.php | 2 +- .../views/components/ui/carrousel.blade.php | 2 +- resources/views/sales/create.blade.php | 12 +- routes/web.php | 32 +++--- 7 files changed, 139 insertions(+), 41 deletions(-) rename resources/views/{catalogo.blade.php => catalogo/index.blade.php} (83%) create mode 100644 resources/views/catalogo/show.blade.php diff --git a/app/Http/Controllers/CatalogoController.php b/app/Http/Controllers/CatalogoController.php index 425580d..8991f3e 100644 --- a/app/Http/Controllers/CatalogoController.php +++ b/app/Http/Controllers/CatalogoController.php @@ -10,7 +10,7 @@ class CatalogoController extends Controller /** * Muestra los registros de ventas con buscador y paginación. */ - public function catalogo(Request $request) + public function index(Request $request) { // Consulta base $query = Product::query(); @@ -31,6 +31,11 @@ class CatalogoController extends Controller $products = $query->paginate(12)->withQueryString(); // withQueryString mantiene la búsqueda al cambiar de página // Devuelve la vista - return view('catalogo', compact('products')); + return view('catalogo.index', compact('products')); + } + + public function show(Product $product) + { + return view('catalogo.show', compact('product')); } } diff --git a/resources/views/catalogo.blade.php b/resources/views/catalogo/index.blade.php similarity index 83% rename from resources/views/catalogo.blade.php rename to resources/views/catalogo/index.blade.php index 0d33c3b..4e22482 100644 --- a/resources/views/catalogo.blade.php +++ b/resources/views/catalogo/index.blade.php @@ -7,11 +7,11 @@ @if ($products->count() > 0)
      - @foreach ($products as $prod) + @foreach ($products as $product)
      {{-- Imagen si existe --}} - @if (!empty($prod->image_path)) - {{ $prod->name }}image_path)) + {{ $product->name }} @else
      @@ -20,22 +20,22 @@ @endif {{-- Nombre --}} -

      {{ $prod->name }}

      +

      {{ $product->name }}

      {{-- Descripción corta --}}
      - @if (!empty($prod->description)) -

      {{ $prod->description }}

      + @if (!empty($product->description)) +

      {{ $product->description }}

      @endif
      {{-- Precio --}} - @if (!empty($prod->price)) -

      ${{ number_format($prod->price, 2, ',', '.') }}

      + @if (!empty($product->price)) +

      ${{ number_format($product->price, 2, ',', '.') }}

      @endif {{-- Botón --}} - Ver + diff --git a/resources/views/catalogo/show.blade.php b/resources/views/catalogo/show.blade.php new file mode 100644 index 0000000..a7834cb --- /dev/null +++ b/resources/views/catalogo/show.blade.php @@ -0,0 +1,105 @@ + + +
      + + + + + Volver al Catálogo + + +
      +
      + + +
      + + @if($product->image_path) + {{ $product->name }} + @else +
      + + Sin Imagen +
      + @endif + + +
      + @if($product->type == 'bike') + Bicicleta + @else + Accesorio + @endif +
      + +
      + + +
      + + +
      +

      SKU: {{ $product->sku ?? 'N/A' }}

      +

      {{ $product->name }}

      + + +
      + @if($product->stock_quantity > 5) + + En Stock ({{ $product->stock_quantity }} unid.) + @elseif($product->stock_quantity > 0) + + ¡Últimas Unidades! ({{ $product->stock_quantity }}) + @else + + Agotado + @endif +
      +
      + + +
      + Precio Contado +
      + ${{ number_format($product->price, 0, ',', '.') }} + ARG +
      +

      * Consultar financiación en el local.

      +
      + + +
      +

      Descripción

      +

      + {{ $product->description ?? 'Sin descripción detallada disponible para este producto. Por favor, acérquese al local para más información.' }} +

      +
      + + +
      + + + + + WhatsApp + +
      + +
      +
      +
      +
      +
      + {{-- Editar +
      + @csrf + @method('DELETE') + +
      --}} \ No newline at end of file diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index 5bc8c95..a3a1721 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -66,7 +66,7 @@
    • -
      +
      diff --git a/resources/views/sales/create.blade.php b/resources/views/sales/create.blade.php index d0bdec9..49d437d 100644 --- a/resources/views/sales/create.blade.php +++ b/resources/views/sales/create.blade.php @@ -38,16 +38,8 @@
      - @if(session('success')) -
      - {{ session('success') }} -
      - @endif - @if(session('error')) -
      - {{ session('error') }} -
      - @endif + + @if($errors->any())
        diff --git a/routes/web.php b/routes/web.php index 74304f5..5e6ba69 100644 --- a/routes/web.php +++ b/routes/web.php @@ -14,31 +14,27 @@ use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Session; Route::get('/',HomeController::class); -Route::get('/catalogo', [CatalogoController::class,'catalogo'])->name('catalogo'); -Route::get('login', function(){ - return view('login'); -})->name('login'); +// Route::get('/catalogo', [CatalogoController::class,'catalogo'])->name('catalogo'); +Route::resource('catalogo', CatalogoController::class)->only(['index', 'show'])->parameters(['catalogo' => 'product']); -Route::post('login', LoginController::class) -->middleware('throttle:5,1') -->name('login.attempt'); - -Route::view('dashboard', 'dashboard')->middleware('auth')->name('dashboard'); - -Route::post('logout', function(){ - Auth::guard('web')->logout(); - - Session::invalidate(); - Session::regenerateToken(); - - return redirect('/'); -})->name('logout'); +Route::get('login', function(){ return view('login'); })->name('login'); +Route::post('login', LoginController::class)->middleware('throttle:5,1')->name('login.attempt'); Route::view('register', 'register')->name('register'); Route::post('register', RegisterController::class)->name('register.store'); +Route::post('logout', function(){ + Auth::guard('web')->logout(); + + Session::invalidate(); + Session::regenerateToken(); + + return redirect('/'); +})->name('logout'); + Route::middleware(['auth'])->group(function () { + Route::view('dashboard', 'dashboard')->name('dashboard'); Route::resource('clients', ClientController::class); Route::resource('productos', ProductosController::class)->parameters([ 'productos' => 'product' From ad852c33d264416b9f3210fc0257e929a514df01 Mon Sep 17 00:00:00 2001 From: BryamE Date: Mon, 12 Jan 2026 13:30:56 -0300 Subject: [PATCH 36/36] cambio ruta --- resources/views/components/ui/carrousel.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/components/ui/carrousel.blade.php b/resources/views/components/ui/carrousel.blade.php index 540b6bd..63d71b1 100644 --- a/resources/views/components/ui/carrousel.blade.php +++ b/resources/views/components/ui/carrousel.blade.php @@ -46,7 +46,7 @@