This commit is contained in:
cmoreno 2026-06-02 20:20:59 -03:00
parent aa46e2dc3f
commit 0b45dd67a5
14 changed files with 578 additions and 126 deletions

Binary file not shown.

Binary file not shown.

View File

@ -5,7 +5,7 @@ namespace App\Http\Controllers;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use App\Models\Categorias; use App\Models\Categorias;
use App\Http\Requests\UpdatedCategoriaRequest;
class CategoriasController extends Controller class CategoriasController extends Controller
{ {
@ -35,6 +35,7 @@ class CategoriasController extends Controller
public function destroy(Request $request, $id){ public function destroy(Request $request, $id){
$categorias = Categorias::findOrfail($id); $categorias = Categorias::findOrfail($id);
$categorias->delete(); $categorias->delete();
$request->session()->flash('mensaje-success', 'La categoría fue eliminada.');
return redirect('/categorias'); return redirect('/categorias');
} }
@ -45,6 +46,18 @@ class CategoriasController extends Controller
public function store(Request $request){ public function store(Request $request){
$request->validate([
'descripcion' => 'required|max:20|',
'nombre' => 'required|unique:categorias,nombre',
],
[
'descripcion.required' => 'el campo descripcion debe ser requerido',
'descripcion.max' => 'el campo descripcion debe contener maximo 10 caracteres',
'nombre.required' => 'el campo nombre es requerido',
'nombre.unique' => 'ya existe una categoria con ese nombre'
]
);
$categorias = new Categorias(); $categorias = new Categorias();
$categorias->fill([ $categorias->fill([
'nombre' => $request->input('nombre'), 'nombre' => $request->input('nombre'),
@ -73,6 +86,7 @@ class CategoriasController extends Controller
public function restaurar(Request $request, $id){ public function restaurar(Request $request, $id){
$categorias = Categorias::withTrashed()->findOrfail($id); $categorias = Categorias::withTrashed()->findOrfail($id);
$categorias->restore(); $categorias->restore();
$request->session()->flash('mensaje-success', 'La categoría fue restaurada.');
return redirect('/categorias'); return redirect('/categorias');
} }

View File

@ -1,35 +1,74 @@
<!doctype html> @extends('layouts.admin')
<html lang="es"> @section('contenido')
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Editar categoría</title>
</head>
<body>
<h1>Editar categoría</h1> <!-- row => fila del sistema de grillas de Bootstrap
justify-content-center => centra horizontalmente el contenido dentro de la fila
align-items-center => alinea verticalmente los elementos de la fila -->
<div class="row justify-content-center align-items-center">
<!-- col-lg-11 col-md-11 col-sm-11 col-xs-11 =>
la columna ocupa 11/12 partes en todos los tamaños de pantalla -->
<div class="col-lg-11 col-md-11 col-sm-11 col-xs-11">
<h3>Editar Categoría</h3>
</div>
</div>
<div class="row">
<div class="col-md-10">
<form method="POST" action="{{ route('categorias.update', $cat->id_categoria) }}"> <!-- Includes de Blade para mensajes de éxito y errores -->
@include('compartido.mensajes')
@include('compartido.errores')
</div>
</div>
<br>
<!-- Formulario de edición de categoría -->
<form method="POST"
action="{{ route('categorias.update', $cat->id_categoria) }}"
enctype="multipart/form-data">
@csrf @csrf
@method('PUT') @method('PUT') <!-- Indica a Laravel que el método real es PUT -->
<div> <!-- row => agrupa los campos en una fila -->
<label for="nombre">Nombre *</label><br> <div class="row">
<input id="nombre" name="nombre" type="text" <!-- form-group => añade márgenes y separación entre los campos -->
value="{{ old('nombre', $cat->nombre) }}" required> <!-- col-md-3 => cada campo ocupa 3/12 columnas en pantallas medianas o más grandes -->
<div class="form-group col-md-3">
<!-- form-check-label => estilo Bootstrap para etiquetas de formulario -->
<label for="nombre" class="form-check-label">Nombre (*)</label>
<!-- form-control => da estilo uniforme al input -->
<input type="text" name="nombre" id="nombre" class="form-control"
value="{{ old('nombre', $cat->nombre) }}" >
</div>
<div class="form-group col-md-3">
<label for="descripcion" class="form-check-label">Descripcion (*)</label>
<input type="text" name="descripcion" id="descripcion" class="form-control"
value="{{ old('descripcion', $cat->descripcion) }}" >
</div>
</div> </div>
<div style="margin-top:8px;"> <!-- row justify-content-center align-items-center =>
<label for="descripcion">Descripción</label><br> fila que centra horizontal y verticalmente los botones -->
<input id="descripcion" name="descripcion" type="text" <div class="row justify-content-center align-items-center">
value="{{ old('descripcion', $cat->descripcion) }}"> <div class="col-md-2">
</div> <!-- btn => clase base de Bootstrap para botones
btn-success => verde (acción positiva)
<div style="margin-top:12px;"> btn-block => ocupa todo el ancho de la columna
<button type="submit">Guardar</button> btn-lg => tamaño grande -->
<a href="{{ route('categorias.index') }}">Volver al listado</a> <button class="btn btn-success btn-block btn-lg">Guardar</button>
</div>
<div class="col-md-2">
<!-- btn-primary => azul (acción principal)
title="Salir" => tooltip al pasar el mouse -->
<a href="{{ route('categorias.index') }}" class="btn btn-primary btn-block btn-lg" title="Salir">Salir</a>
</div>
</div> </div>
</form> </form>
</body> @endsection
</html>
@push('scripts')
<script>
//Aquí se pueden agregar scripts específicos de esta vista -->
</script>
@endpush

View File

@ -0,0 +1,35 @@
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Editar categoría</title>
</head>
<body>
<h1>Editar categoría</h1>
<form method="POST" action="{{ route('categorias.update', $cat->id_categoria) }}">
@csrf
@method('PUT')
<div>
<label for="nombre">Nombre *</label><br>
<input id="nombre" name="nombre" type="text"
value="{{ old('nombre', $cat->nombre) }}" required>
</div>
<div style="margin-top:8px;">
<label for="descripcion">Descripción</label><br>
<input id="descripcion" name="descripcion" type="text"
value="{{ old('descripcion', $cat->descripcion) }}">
</div>
<div style="margin-top:12px;">
<button type="submit">Guardar</button>
<a href="{{ route('categorias.index') }}">Volver al listado</a>
</div>
</form>
</body>
</html>

View File

@ -1,50 +1,128 @@
<!doctype html> @extends('layouts.admin')
<html lang="es"> @section('contenido')
<head>
<title>Categorías</title>
</head>
<body>
<p>
<a href="{{ route('categorias.create') }}">Nueva categoría</a>
</p>
<ul>
@foreach($categorias as $cat)
<li>
<strong>{{ $cat->nombre }}</strong>
{{ $cat->descripcion }}
(ID: {{ $cat->id_categoria}})
&nbsp;|&nbsp;
@if($cat->deleted_at == null)
<a href="{{ route('categorias.show', $cat->id_categoria) }}">Ver Más</a>
&nbsp;|&nbsp;
<a href="{{ route('categorias.edit', $cat->id_categoria) }}">Editar </a>
<form action="{{ route('categorias.destroy', $cat->id_categoria) }}"
method="POST" >
@csrf
@method('DELETE')
<button onclick="return confirm('¿Eliminar esta categoría?')">
Eliminar
</button>
</form>
@else
<form action="{{ route('categorias.restaurar', $cat->id_categoria) }}"
method="POST" >
@csrf
@method('PUT')
<button onclick="return confirm('¿Restaurar esta categoría?')">
Restaurar Cat
</button>
</form>
@endif <!-- row => fila del sistema de grillas Bootstrap
justify-content-center => centra horizontalmente los contenidos
align-items-center => centra verticalmente
no centran el texto, centran las columnas dentro de la fila
-->
<div class="row justify-content-center align-items-center">
<!-- col-12 => ocupa todo el ancho en pantallas pequeñas
col-md-11 => ocupa 11/12 del ancho en pantallas medianas o mayores -->
<div class="col-12 col-md-11">
<h3>Listado de Categorías</h3>
</div>
</div>
<div class="row justify-content-center align-items-center">
<div class="col-md-2">
<!-- btn => estilo de botón Bootstrap
btn-success => verde (acción positiva)
btn-block => ocupa todo el ancho de la columna
btn-lg => tamaño grande -->
<a href="{{ route('categorias.create') }}"
class="btn btn-success btn-block btn-lg"
title="Nueva Categoria">
Nuevo
</a>
</div>
</div>
{{--<a href="{{ route('categorias.edit', $cat->id_categoria) }}">Editar</a> <br>
--}}
</li>
@endforeach
</ul>
</body> <div class="row justify-content-center align-items-center">
</html> <div class="col-12 col-md-11">
<!-- Includes de Blade para mensajes de éxito y errores -->
@include('compartido.mensajes')
@include('compartido.errores')
<!-- table-responsive => hace que la tabla sea "scrollable" en pantallas pequeñas -->
<div class="table-responsive">
<!-- table => tabla con estilos básicos
table-striped => filas alternadas con fondo gris
table-bordered => agrega bordes a todas las celdas
table-hover => resalta la fila al pasar el mouse -->
<table class="table table-striped table-bordered table-hover" id="example">
<thead>
<tr>
<th>Id</th>
<th>Nombre</th>
<th>Descripcion</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
@foreach($categorias as $cat)
<tr>
<td>{{ $cat->id_categoria }}</td>
<td>{{ $cat->nombre }}</td>
<td>{{ $cat->descripcion }}</td>
<td align="center">
@if($cat->deleted_at == null)
<form method="POST" action="{{ route('categorias.destroy', $cat->id_categoria) }}" style="display:inline;">
@csrf
@method('DELETE')
<!-- btn-info => azul claro (información) -->
<a class="btn btn-info"
href="{{ route('categorias.show', $cat->id_categoria) }}"
title="Ver más">
<i class="fa fa-eye"></i>
</a>
<!-- btn-warning => amarillo (advertencia / editar) -->
<a class="btn btn-warning"
href="{{ route('categorias.edit', $cat->id_categoria) }}"
title="Editar">
<i class="fa fa-pencil"></i>
</a>
<!-- btn-danger => rojo (acción destructiva como eliminar) -->
<button class="btn btn-danger"
onclick="return confirm('¿Está seguro de eliminar la categoría?');"
title="Eliminar">
<i class="fa fa-remove"></i>
</button>
</form>
@else
<form method="POST" action="{{ route('categorias.restaurar', $cat->id_categoria) }}" style="display:inline;">
@csrf
@method('PUT')
<!-- btn-danger => rojo (acción destructiva como eliminar) -->
<button class="btn btn-success"
onclick="return confirm('¿Está seguro de Restaurar la categoría?');"
title="Restaurar">
<i class="fa fa-undo"></i>
</button>
</form>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
@endsection
@push('styles')
@endpush
@push('scripts')
<script>
// DataTables (plugin JS para mejorar tablas: búsqueda, paginación, exportación)
$('#example').DataTable({
dom: 'Bfrtip',
buttons: ['excel'],
pageLength: 5,
});
</script>
@endpush

View File

@ -0,0 +1,50 @@
<!doctype html>
<html lang="es">
<head>
<title>Categorías</title>
</head>
<body>
<p>
<a href="{{ route('categorias.create') }}">Nueva categoría</a>
</p>
<ul>
@foreach($categorias as $cat)
<li>
<strong>{{ $cat->nombre }}</strong>
{{ $cat->descripcion }}
(ID: {{ $cat->id_categoria}})
&nbsp;|&nbsp;
@if($cat->deleted_at == null)
<a href="{{ route('categorias.show', $cat->id_categoria) }}">Ver Más</a>
&nbsp;|&nbsp;
<a href="{{ route('categorias.edit', $cat->id_categoria) }}">Editar </a>
<form action="{{ route('categorias.destroy', $cat->id_categoria) }}"
method="POST" >
@csrf
@method('DELETE')
<button onclick="return confirm('¿Eliminar esta categoría?')">
Eliminar
</button>
</form>
@else
<form action="{{ route('categorias.restaurar', $cat->id_categoria) }}"
method="POST" >
@csrf
@method('PUT')
<button onclick="return confirm('¿Restaurar esta categoría?')">
Restaurar Cat
</button>
</form>
@endif
{{--<a href="{{ route('categorias.edit', $cat->id_categoria) }}">Editar</a>
--}}
</li>
@endforeach
</ul>
</body>
</html>

View File

@ -1,32 +1,70 @@
<!doctype html> @extends('layouts.admin')
<html lang="es"> @section ('contenido')
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Nueva categoría</title>
</head>
<body>
<h1>Nueva categoría</h1> <!-- row => fila del sistema de grillas de Bootstrap
justify-content-center => centra horizontalmente el contenido dentro de la fila
align-items-center => centra verticalmente los elementos dentro de la fila -->
<div class="row justify-content-center align-items-center">
<!-- col-lg-11 col-md-11 col-sm-11 col-xs-11 =>
la columna ocupa 11/12 partes del ancho en todos los tamaños de pantalla -->
<div class="col-lg-11 col-md-11 col-sm-11 col-xs-11">
<h3>Nueva Categoría</h3>
</div>
</div>
<div class="row">
<div class="col-md-10">
<form method="POST" action="{{ route('categorias.store') }}"> <!-- Includes de Blade para mensajes de éxito y errores -->
@csrf @include('compartido.mensajes')
@include('compartido.errores')
</div>
</div>
</br>
<div> <!-- Formulario para crear nueva categoría -->
<label for="nombre">Nombre *</label><br> <form method="post" action="{{ route('categorias.store') }}" enctype=multipart/form-data>
<input id="nombre" name="nombre" type="text" value="{{ old('nombre') }}" required> @csrf
</div>
<!-- row => agrupa los campos en una fila -->
<div class="row">
<!-- form-group => separa cada campo del formulario con márgenes
col-md-3 => ocupa 3/12 columnas en pantallas medianas hacia arriba -->
<div class="form-group col-md-3">
<!-- form-check-label => clase de Bootstrap que estiliza etiquetas de formulario -->
<label for="nombre" class="form-check-label">Nombre (*)</label>
<!-- form-control => aplica estilos consistentes al input-->
<input type="text" name="nombre" id="nombre" value="{{old('nombre')}}" required class="form-control" >
</div>
<div style="margin-top:8px;"> <div class="form-group col-md-3">
<label for="descripcion">Descripción</label><br> <label for="descripcion" class="form-check-label">Descripcion (*)</label>
<input id="descripcion" name="descripcion" type="text" value="{{ old('descripcion') }}"> <input type="text" name="descripcion" id="descripcion" value="{{old('descripcion')}}" class="form-control">
</div> </div>
</div>
<div style="margin-top:12px;">
<button type="submit">Guardar</button> <!-- row justify-content-center align-items-center =>
<a href="{{ route('categorias.index') }}">Volver al listado</a> crea una fila y centra horizontal y verticalmente los botones -->
</div> <div class="row justify-content-center align-items-center">
<div class="col-md-2">
<!-- btn => botón base de Bootstrap
btn-success => color verde
btn-block => ocupa todo el ancho de la columna
btn-lg => tamaño grande -->
<button class="btn btn-success btn-block btn-lg">Guardar</button>
</div>
<div class="col-md-2">
<!-- btn-primary => color azul
title="Salir" => muestra tooltip al pasar el mouse -->
<a href="{{ route('categorias.index') }}" class="btn btn-primary btn-block btn-lg" title="Salir">Salir</a>
</div>
</div>
</form> </form>
</body> @endsection
</html>
@push('scripts')
<script>
//Aquí podrías agregar código JavaScript específico para esta vista
</script>
@endpush

View File

@ -0,0 +1,32 @@
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Nueva categoría</title>
</head>
<body>
<h1>Nueva categoría</h1>
<form method="POST" action="{{ route('categorias.store') }}">
@csrf
<div>
<label for="nombre">Nombre *</label><br>
<input id="nombre" name="nombre" type="text" value="{{ old('nombre') }}" required>
</div>
<div style="margin-top:8px;">
<label for="descripcion">Descripción</label><br>
<input id="descripcion" name="descripcion" type="text" value="{{ old('descripcion') }}">
</div>
<div style="margin-top:12px;">
<button type="submit">Guardar</button>
<a href="{{ route('categorias.index') }}">Volver al listado</a>
</div>
</form>
</body>
</html>

View File

@ -1,31 +1,28 @@
<!doctype html> @extends('layouts.admin')
<html lang="es"> @section ('contenido')
<head> <div class="row justify-content-center align-items-center">
<meta charset="utf-8"> <div class="col-lg-11 col-md-11 col-sm-11 col-xs-11">
<meta name="viewport" content="width=device-width, initial-scale=1"> <h3>Ver Categoría</h3>
<title>Ver categoría</title> <div class="progress" style="height: 2px;"></div>
</head> </div>
<body> </div>
</br>
<div class="row">
<div class="form-group col-md-3">
<label for="nombre" class="form-check-label">Nombre (*)</label>
<input type="text" name="nombre" id="nombre" class="form-control" value="{{$cat->nombre}}" readonly>
</div>
<div class="form-group col-md-3">
<label for="descripcion" class="form-check-label">Nombre (*)</label>
<input type="text" name="descripcion" id="descripcion" class="form-control" value="{{$cat->descripcion}}" readonly>
</div>
</div>
<h1>Ver categoría</h1> <legend></legend>
<div class="row justify-content-center align-items-center">
<div class="col-md-2">
<a href="{{ route('categorias.index') }}" class="btn btn-primary btn-block btn-lg" title="Salir">Salir</a>
</div>
</div>
@endsection
<div>
<label for="nombre">Nombre *</label><br>
<input id="nombre" name="nombre" readonly type="text"
value="{{ $cat->nombre }}" >
</div>
<div style="margin-top:8px;">
<label for="descripcion">Descripción</label><br>
<input id="descripcion" readonly name="descripcion" type="text"
value="{{ $cat->descripcion }}">
</div>
<div style="margin-top:12px;">
<a href="{{ route('categorias.index') }}">Volver al listado</a>
</div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ver categoría</title>
</head>
<body>
<h1>Ver categoría</h1>
<div>
<label for="nombre">Nombre *</label><br>
<input id="nombre" name="nombre" readonly type="text"
value="{{ $cat->nombre }}" >
</div>
<div style="margin-top:8px;">
<label for="descripcion">Descripción</label><br>
<input id="descripcion" readonly name="descripcion" type="text"
value="{{ $cat->descripcion }}">
</div>
<div style="margin-top:12px;">
<a href="{{ route('categorias.index') }}">Volver al listado</a>
</div>
</body>
</html>

View File

@ -0,0 +1,9 @@
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif

View File

@ -0,0 +1,3 @@
@if (session('mensaje-success'))
<p class="alert alert-success">{{ session('mensaje-success') }}</p>
@endif

View File

@ -0,0 +1,126 @@
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<!-- viewport => hace que el sitio sea responsive en móviles -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Token CSRF de Laravel para proteger formularios -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<!-- yield => permite que cada vista defina su título; si no lo define, se usa "MiApp" -->
<title>@yield('title','Sistema Taller')</title>
<!-- Bootstrap CSS v4.6.2:
- framework que da estilos listos para botones, formularios, grillas, etc. -->
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<!-- FontAwesome:
- librería de íconos (ej: fa-eye, fa-pencil, fa-remove, etc.). -->
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<!-- DataTables: -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.8/css/dataTables.bootstrap4.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/buttons/2.4.2/css/buttons.bootstrap4.min.css">
<!-- @stack('styles') => permite que otras vistas agreguen CSS extra en esta sección -->
@stack('styles')
</head>
<body>
<!-- navbar => barra de navegación de Bootstrap -->
<!-- navbar-expand-lg => se expande en pantallas grandes (LG) -->
<!-- navbar-light => estilo de texto oscuro sobre fondo claro -->
<!-- bg-light => fondo gris claro -->
<nav class="navbar navbar-expand-lg bg-light">
<!-- Nombre de la aplicación -->
<a class="navbar-brand" href="{{ url('/') }}">
MiApp
</a>
<!-- Menú principal -->
<ul class="navbar-nav">
<!-- Categorías -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle"
href="#"
data-toggle="dropdown">
Categorías
</a>
<div class="dropdown-menu">
<a class="dropdown-item"
href="{{ route('categorias.index') }}">
Listado
</a>
<a class="dropdown-item"
href="{{ route('categorias.create') }}">
Nueva Categoría
</a>
</div>
</li>
<!-- Usuarios -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle"
href="#"
data-toggle="dropdown">
Usuarios
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">
Listado
</a>
<a class="dropdown-item" href="#">
Nuevo Usuario
</a>
</div>
</li>
</ul>
</nav>
<!-- container => centra el contenido y le da márgenes automáticos laterales -->
<!-- py-4 => padding vertical (arriba y abajo) de 1.5rem (~24px) -->
<div class="container py-4">
<!-- yield('contenido') => espacio donde cada vista Blade inyecta su propio contenido -->
@yield('contenido')
</div>
<!-- Dependencias JS -->
<!-- jQuery => requerido por Bootstrap 4 -->
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<!-- Popper.js => requerido para tooltips, dropdowns y menús flotantes -->
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<!-- Bootstrap JS => activa componentes interactivos como modales, menús, tooltips -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.min.js"></script>
<!-- DataTables -->
<script src="https://cdn.datatables.net/1.13.8/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.8/js/dataTables.bootstrap4.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.bootstrap4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.html5.min.js"></script>
<!-- stack('scripts') => permite que otras vistas agreguen scripts extra -->
@stack('scripts')
</body>
</html>