From 3aba95bc913d199d622c0212b9389c52669c21ae Mon Sep 17 00:00:00 2001 From: Bryam105 Date: Mon, 25 May 2026 19:42:09 -0300 Subject: [PATCH 1/4] CAMBIOS: - Creada pagina de FAQ con manual de funcionalidades. - Arregladas alertas de exito y error en CDE de todos los elementos. - Creada alerta de verificacion en la eliminacion de cualquier elemento. --- resources/views/catalogo/show.blade.php | 2 +- resources/views/clients/index.blade.php | 10 +- resources/views/components/layout.blade.php | 3 + resources/views/components/navbar.blade.php | 6 + resources/views/components/ui/alert.blade.php | 33 +++-- .../components/ui/confirm-delete.blade.php | 80 ++++++++++++ resources/views/faq.blade.php | 123 ++++++++++++++++++ resources/views/productos/create.blade.php | 6 +- resources/views/productos/edit.blade.php | 5 - resources/views/productos/index.blade.php | 4 +- resources/views/productos/show.blade.php | 7 - resources/views/sales.blade.php | 2 +- resources/views/sales/create.blade.php | 2 +- resources/views/sales/show.blade.php | 2 +- resources/views/suppliers/index.blade.php | 15 +-- resources/views/taller/create.blade.php | 2 +- resources/views/taller/index.blade.php | 6 +- routes/web.php | 1 + 18 files changed, 253 insertions(+), 56 deletions(-) create mode 100644 resources/views/components/ui/confirm-delete.blade.php create mode 100644 resources/views/faq.blade.php diff --git a/resources/views/catalogo/show.blade.php b/resources/views/catalogo/show.blade.php index cfc1485..4fa2ddf 100644 --- a/resources/views/catalogo/show.blade.php +++ b/resources/views/catalogo/show.blade.php @@ -102,7 +102,7 @@ {{-- Editar -
+ @csrf @method('DELETE') +
+ +

¿Estás seguro de que quieres eliminar este registro?

+

Esta acción no se puede deshacer.

+ + +
+ + + + + diff --git a/resources/views/faq.blade.php b/resources/views/faq.blade.php new file mode 100644 index 0000000..e0cefe4 --- /dev/null +++ b/resources/views/faq.blade.php @@ -0,0 +1,123 @@ + + + +
+ + +
+
+

+ + + + Manual de Uso Rápido +

+

Conceptos básicos para navegar por el sistema Lauck.

+
+
+ +
+
1
+
+

Dashboard

+

El panel principal muestra un resumen de las métricas clave, accesos directos a tus módulos más importantes y un panorama general del negocio.

+
+
+ +
+
2
+
+

Stock y Productos

+

Registra bicicletas, accesorios y repuestos. Mantén las cantidades actualizadas para evitar quiebres de inventario mediante la gestión de tu stock.

+
+
+ +
+
3
+
+

Taller

+

Administra la agenda de reparaciones, asigna estados (pendiente, en proceso, listo) y mantén un registro de los servicios realizados a cada cliente.

+
+
+ +
+
4
+
+

Ventas y Clientes

+

Genera nuevas ventas, consulta el historial, y gestiona la base de datos de tus clientes para ofrecer un servicio más personalizado.

+
+
+
+
+ + +

+ + + + Preguntas Frecuentes (FAQ) +

+ +
+ +
+ + ¿Cómo agrego un nuevo producto al stock? + + + + +
+

Dirígete a la sección Stock desde el menú principal, haz clic en el botón superior derecho de agregar nuevo producto y completa el formulario con los detalles (SKU, nombre, precio, etc).

+
+
+ + +
+ + ¿Puedo registrar una venta si el cliente no está registrado? + + + + +
+

Sí, al crear una nueva venta desde la sección Ventas puedes seleccionar un cliente genérico ("Consumidor Final") o bien ingresar los datos de un cliente nuevo en el mismo momento para que quede registrado en tu base de datos.

+
+
+ + +
+ + ¿Qué pasa si olvido mi contraseña? + + + + +
+

En la pantalla de inicio de sesión, haz clic en el enlace "¿Olvidaste tu contraseña?". Te enviaremos un correo electrónico con instrucciones para restablecerla de forma segura. Si el problema persiste, contacta al administrador del sistema.

+
+
+ + +
+ + ¿Cómo cambiar entre modo claro y oscuro? + + + + +
+

En la barra de navegación superior (Navbar), encontrarás un icono de un sol o una luna (dependiendo del modo actual en el que te encuentres). Haz clic sobre el ícono para alternar entre el tema claro y el oscuro. El sistema recordará tu preferencia para futuras sesiones.

+
+
+
+ +
+

¿Necesitas más ayuda?

+

Si tienes alguna otra duda o experimentas problemas técnicos, nuestro equipo de soporte está disponible para ayudarte.

+ + Contactar a Soporte + +
+
+
diff --git a/resources/views/productos/create.blade.php b/resources/views/productos/create.blade.php index 2d626f0..fddc91e 100644 --- a/resources/views/productos/create.blade.php +++ b/resources/views/productos/create.blade.php @@ -53,11 +53,7 @@ - -
- - -
+
diff --git a/resources/views/productos/edit.blade.php b/resources/views/productos/edit.blade.php index c419ef2..a2e279f 100644 --- a/resources/views/productos/edit.blade.php +++ b/resources/views/productos/edit.blade.php @@ -52,11 +52,6 @@
- -
- - -
diff --git a/resources/views/productos/index.blade.php b/resources/views/productos/index.blade.php index 5340808..9ab6e84 100644 --- a/resources/views/productos/index.blade.php +++ b/resources/views/productos/index.blade.php @@ -2,7 +2,7 @@ - +
@@ -114,7 +114,7 @@ - + @csrf @method('DELETE')
-
- -
- {{ $product->description ?: 'No hay descripción cargada para este producto.' }} -
-
-
diff --git a/resources/views/sales.blade.php b/resources/views/sales.blade.php index 40a18ab..a892a17 100644 --- a/resources/views/sales.blade.php +++ b/resources/views/sales.blade.php @@ -2,7 +2,7 @@ - +
diff --git a/resources/views/sales/create.blade.php b/resources/views/sales/create.blade.php index 7a16985..4d0af5c 100644 --- a/resources/views/sales/create.blade.php +++ b/resources/views/sales/create.blade.php @@ -85,7 +85,7 @@ - + @if($errors->any())
diff --git a/resources/views/sales/show.blade.php b/resources/views/sales/show.blade.php index 9271fa9..cf0d76e 100644 --- a/resources/views/sales/show.blade.php +++ b/resources/views/sales/show.blade.php @@ -1,7 +1,7 @@ - +
diff --git a/resources/views/suppliers/index.blade.php b/resources/views/suppliers/index.blade.php index 7fd2443..a11018f 100644 --- a/resources/views/suppliers/index.blade.php +++ b/resources/views/suppliers/index.blade.php @@ -2,17 +2,8 @@ - - @if(session('success')) -
- {{ session('success') }} -
- @endif - + +
@@ -79,7 +70,7 @@ - + @csrf @method('DELETE') + {{-- LÓGICA DE VISITANTE (GUEST) --}} @guest diff --git a/resources/views/components/taller-card.blade.php b/resources/views/components/taller-card.blade.php index 757920e..239a7e7 100644 --- a/resources/views/components/taller-card.blade.php +++ b/resources/views/components/taller-card.blade.php @@ -9,33 +9,33 @@ }; @endphp -
+
- {{ $job->client->name }} - {{ $job->scheduled_at->format('d/m H:i') }} + {{ $job->client->name }} + {{ $job->scheduled_at->format('d/m H:i') }}
-

{{ $job->bike_model }}

-

{{ $job->problem_description }}

+

{{ $job->bike_model }}

+

{{ $job->problem_description }}

@if($job->estimated_cost)
- Presupuesto: - ${{ number_format($job->estimated_cost, 0) }} + Presupuesto: + ${{ number_format($job->estimated_cost, 0) }}
@endif -
+
@if($job->status !== 'pending') @csrf @method('PATCH') - @@ -44,9 +44,9 @@ @endif - - - Avisar + + + Avisar @@ -54,7 +54,7 @@
@csrf @method('PATCH') -
@@ -63,7 +63,7 @@
@csrf @method('PATCH') -
diff --git a/resources/views/taller/create.blade.php b/resources/views/taller/create.blade.php index 2190c44..e3b413d 100644 --- a/resources/views/taller/create.blade.php +++ b/resources/views/taller/create.blade.php @@ -14,19 +14,19 @@
@endif -
+
@csrf -
-

- 1 Cliente +
+

+ 1 Cliente

- - @foreach($clients as $client) @@ -38,41 +38,41 @@ + Nuevo Cliente
- + - +
-
-

- 2 Diagnóstico y Repuestos +
+

+ 2 Diagnóstico y Repuestos

- - + +
- - + +
-
- +
+
- + - +
@@ -88,29 +88,29 @@
-

- 3 Acuerdo +

+ 3 Acuerdo

- - + +
-
- +
+
$ - +

* Calculado automáticamente según repuestos. Editable.

-
- Cancelar +
+ Cancelar @@ -154,10 +154,10 @@ if (matches.length > 0) { matches.forEach(p => { html += ` -
${p.name} - $${p.price} + $${p.price}
`; }); } else { @@ -215,8 +215,8 @@ // Visual $container.append(` -
-
+
+
${p.name} ($${p.price})
diff --git a/resources/views/taller/index.blade.php b/resources/views/taller/index.blade.php index 78ba7f2..4da8218 100644 --- a/resources/views/taller/index.blade.php +++ b/resources/views/taller/index.blade.php @@ -19,10 +19,10 @@
-
-
-

🔴 Pendientes / A Revisar

- {{ $pending->count() }} +
+
+

🔴 Pendientes / A Revisar

+ {{ $pending->count() }}
@foreach($pending as $job) @@ -32,10 +32,10 @@
-
-
-

🟡 En Reparación

- {{ $inProgress->count() }} +
+
+

🟡 En Reparación

+ {{ $inProgress->count() }}
@foreach($inProgress as $job) @@ -45,10 +45,10 @@
-
-
-

🟢 Listas para Retirar

- {{ $ready->count() }} +
+
+

🟢 Listas para Retirar

+ {{ $ready->count() }}
@foreach($ready as $job) From f03890b348cd0c93d3eb8ec0717810d4fdb554b2 Mon Sep 17 00:00:00 2001 From: Bryam105 Date: Wed, 27 May 2026 08:57:20 -0300 Subject: [PATCH 3/4] CAMBIOS: - Agregado el autocompletado de direcciones. - Validacion de numeros en el nombre. --- app/Http/Controllers/ClientController.php | 8 ++- resources/views/clients/create.blade.php | 77 ++++++++++++++++++++++- resources/views/clients/edit.blade.php | 76 +++++++++++++++++++++- 3 files changed, 155 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index 948ae5e..cb8e726 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -40,10 +40,12 @@ class ClientController extends Controller public function store(Request $request) { $validated = $request->validate([ - 'name' => 'required|string|max:255', + 'name' => ['required', 'string', 'max:255', 'not_regex:/[0-9]/'], 'phone' => 'nullable|string|max:50', 'email' => 'nullable|email|max:255|unique:clients,email', 'address' => 'nullable|string|max:255', + ], [ + 'name.not_regex' => 'El nombre del cliente no puede contener números.', ]); // 1. Guardamos el cliente en una variable para tener su ID @@ -88,10 +90,12 @@ class ClientController extends Controller public function update(Request $request, Client $client) { $validated = $request->validate([ - 'name' => 'required|string|max:255', + 'name' => ['required', 'string', 'max:255', 'not_regex:/[0-9]/'], 'phone' => 'nullable|string|max:50', 'email' => 'nullable|email|max:255|unique:clients,email,' . $client->id, // Ignorar email propio 'address' => 'nullable|string|max:255', + ], [ + 'name.not_regex' => 'El nombre del cliente no puede contener números.', ]); $client->update($validated); diff --git a/resources/views/clients/create.blade.php b/resources/views/clients/create.blade.php index e97d183..f227dd0 100644 --- a/resources/views/clients/create.blade.php +++ b/resources/views/clients/create.blade.php @@ -23,9 +23,13 @@
-
+
- + + + + + @error('address') {{ $message }} @enderror @@ -41,4 +45,73 @@
+ + @push('scripts') + + @endpush \ No newline at end of file diff --git a/resources/views/clients/edit.blade.php b/resources/views/clients/edit.blade.php index b3137fd..2a27041 100644 --- a/resources/views/clients/edit.blade.php +++ b/resources/views/clients/edit.blade.php @@ -23,10 +23,13 @@
-
+
- + + + + @error('address') {{ $message }} @enderror @@ -42,4 +45,73 @@
+ + @push('scripts') + + @endpush \ No newline at end of file From 8ad829d9d2967ffd903e8a42cfb08b8e853ec495 Mon Sep 17 00:00:00 2001 From: Bryam105 Date: Wed, 27 May 2026 09:50:00 -0300 Subject: [PATCH 4/4] =?UTF-8?q?NUEVO:=20-=20Agregada=20nueva=20funcionalid?= =?UTF-8?q?ad=20de=20"Forgot=20Password"=20para=20reestablecer=20la=20cont?= =?UTF-8?q?rase=C3=B1a.=20-=20Cambios=20en=20estilos=20del=20login=20para?= =?UTF-8?q?=20mayor=20consistencia=20con=20el=20resto=20de=20la=20pagina.?= =?UTF-8?q?=20-=20Creado=20correo=20con=20template=20propio=20fiel=20al=20?= =?UTF-8?q?estilo=20de=20la=20pagina.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/NewPasswordController.php | 45 ++++++++++++ .../PasswordResetLinkController.php | 31 ++++++++ app/Models/User.php | 12 ++++ .../ResetPasswordNotification.php | 26 +++++++ .../views/auth/forgot-password.blade.php | 51 +++++++++++++ resources/views/auth/reset-password.blade.php | 56 +++++++++++++++ .../views/emails/reset-password.blade.php | 71 +++++++++++++++++++ resources/views/login.blade.php | 61 ++++++++++------ routes/web.php | 16 +++++ 9 files changed, 349 insertions(+), 20 deletions(-) create mode 100644 app/Http/Controllers/NewPasswordController.php create mode 100644 app/Http/Controllers/PasswordResetLinkController.php create mode 100644 app/Notifications/ResetPasswordNotification.php create mode 100644 resources/views/auth/forgot-password.blade.php create mode 100644 resources/views/auth/reset-password.blade.php create mode 100644 resources/views/emails/reset-password.blade.php diff --git a/app/Http/Controllers/NewPasswordController.php b/app/Http/Controllers/NewPasswordController.php new file mode 100644 index 0000000..e7e01c4 --- /dev/null +++ b/app/Http/Controllers/NewPasswordController.php @@ -0,0 +1,45 @@ + $request, 'token' => $token]); + } + + public function store(Request $request) + { + $request->validate([ + 'token' => 'required', + 'email' => 'required|email', + 'password' => 'required|min:8|confirmed', + ]); + + $status = Password::reset( + $request->only('email', 'password', 'password_confirmation', 'token'), + function ($user, $password) { + $user->forceFill([ + 'password' => Hash::make($password) + ])->setRememberToken(Str::random(60)); + + $user->save(); + + event(new PasswordReset($user)); + } + ); + + if ($status == Password::PASSWORD_RESET) { + return redirect()->route('login')->with('status', __($status)); + } + + return back()->withErrors(['email' => [__($status)]]); + } +} diff --git a/app/Http/Controllers/PasswordResetLinkController.php b/app/Http/Controllers/PasswordResetLinkController.php new file mode 100644 index 0000000..cca2052 --- /dev/null +++ b/app/Http/Controllers/PasswordResetLinkController.php @@ -0,0 +1,31 @@ +validate([ + 'email' => 'required|email', + ]); + + $status = Password::sendResetLink( + $request->only('email') + ); + + if ($status == Password::RESET_LINK_SENT) { + return back()->with('status', __($status)); + } + + return back()->withErrors(['email' => __($status)]); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 5c0bb00..d806001 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -6,6 +6,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; +use App\Notifications\ResetPasswordNotification; class User extends Authenticatable { @@ -45,4 +46,15 @@ class User extends Authenticatable 'password' => 'hashed', ]; } + + /** + * Send the password reset notification. + * + * @param string $token + * @return void + */ + public function sendPasswordResetNotification($token) + { + $this->notify(new ResetPasswordNotification($token)); + } } diff --git a/app/Notifications/ResetPasswordNotification.php b/app/Notifications/ResetPasswordNotification.php new file mode 100644 index 0000000..d2bcfeb --- /dev/null +++ b/app/Notifications/ResetPasswordNotification.php @@ -0,0 +1,26 @@ + $this->token, + 'email' => $notifiable->getEmailForPasswordReset(), + ], false)); + + return (new MailMessage) + ->subject('Recuperación de Contraseña - Lauck') + ->view('emails.reset-password', [ + 'url' => $url, + ]); + } +} diff --git a/resources/views/auth/forgot-password.blade.php b/resources/views/auth/forgot-password.blade.php new file mode 100644 index 0000000..3c6e665 --- /dev/null +++ b/resources/views/auth/forgot-password.blade.php @@ -0,0 +1,51 @@ + +
+ + +
+
+ ¿Olvidaste tu contraseña? No hay problema. Simplemente déjanos saber tu dirección de correo electrónico y te enviaremos un enlace para restablecer la contraseña que te permitirá elegir una nueva. +
+ + @if (session('status')) +
+ {{ session('status') }} +
+ @endif + +
+ @csrf + + @if ($errors->any()) +
+

+ {{ $errors->first() }} +

+
+ @endif + + +
+ + +
+ +
+ + Volver a inicio de sesión + + + +
+
+
+
+
diff --git a/resources/views/auth/reset-password.blade.php b/resources/views/auth/reset-password.blade.php new file mode 100644 index 0000000..7c7eb32 --- /dev/null +++ b/resources/views/auth/reset-password.blade.php @@ -0,0 +1,56 @@ + +
+ + +
+
+ @csrf + + + + + @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ +
+
+
+
+
diff --git a/resources/views/emails/reset-password.blade.php b/resources/views/emails/reset-password.blade.php new file mode 100644 index 0000000..c7795fa --- /dev/null +++ b/resources/views/emails/reset-password.blade.php @@ -0,0 +1,71 @@ + + + + + + Recuperar Contraseña + + + + + + +
+ + + + + + + + + + + + + + + + + +
+

+ Bicicletería Lauck +

+

Recuperación de cuenta

+
+

+ Hola, +

+

+ Estás recibiendo este correo porque recibimos una solicitud de restablecimiento de contraseña para tu cuenta en Lauck. +

+ + + + + +
+ + Restablecer Contraseña + +
+ +

+ Este enlace para restablecer la contraseña caducará en 60 minutos. +

+

+ Si no solicitaste un restablecimiento de contraseña, no es necesario realizar ninguna otra acción. +

+
+

+ Si tienes problemas para hacer clic en el botón "Restablecer Contraseña", copia y pega la siguiente URL en tu navegador web:
+ {{ $url }} +

+
+

+ © {{ date('Y') }} Bicicletería Lauck. Todos los derechos reservados. +

+
+ + diff --git a/resources/views/login.blade.php b/resources/views/login.blade.php index 9e0bc6b..ad06a6e 100644 --- a/resources/views/login.blade.php +++ b/resources/views/login.blade.php @@ -1,44 +1,65 @@ -
- -
-
+
+ + +
+ @csrf + {{-- Bloque de errores --}} @if ($errors->any()) -
+

{{ $errors->first() }}

@endif + + @if (session('status')) +
+

+ {{ session('status') }} +

+
+ @endif
- Correo electrónico - + +
- Contraseña - + + + +
- +
-

- ¿No tienes una cuenta? Regístrate acá. -

+
+

+ ¿No tienes una cuenta? Regístrate acá. +

+
+ \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index e5ee711..51f733a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -13,6 +13,8 @@ use App\Http\Controllers\TallerController; use App\Http\Controllers\AgendaController; use App\Http\Controllers\AppointmentController; use App\Http\Controllers\SupplierController; +use App\Http\Controllers\PasswordResetLinkController; +use App\Http\Controllers\NewPasswordController; use App\Models\Product; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Session; @@ -25,6 +27,20 @@ Route::resource('catalogo', CatalogoController::class)->only(['index', 'show'])- Route::get('login', function(){ return view('login'); })->name('login'); Route::post('login', LoginController::class)->middleware('throttle:5,1')->name('login.attempt'); +Route::middleware('guest')->group(function () { + Route::get('forgot-password', [PasswordResetLinkController::class, 'create']) + ->name('password.request'); + + Route::post('forgot-password', [PasswordResetLinkController::class, 'store']) + ->name('password.email'); + + Route::get('reset-password/{token}', [NewPasswordController::class, 'create']) + ->name('password.reset'); + + Route::post('reset-password', [NewPasswordController::class, 'store']) + ->name('password.store'); +}); + Route::view('register', 'register')->name('register'); Route::post('register', RegisterController::class)->name('register.store');