Browse Source
hice la tabla de usuarios, hice la pagina de marcas con todos sus campos y requirimientos, etc etcmain
14 changed files with 623 additions and 22 deletions
@ -0,0 +1,97 @@ |
|||
<?php |
|||
|
|||
namespace App\Http\Controllers; |
|||
|
|||
use App\Models\Marca; |
|||
use Illuminate\Http\Request; |
|||
|
|||
class MarcaController extends Controller |
|||
{ |
|||
/** |
|||
* Display a listing of the resource. |
|||
*/ |
|||
public function index(Request $request) |
|||
{ |
|||
$busqueda = $request->busqueda; |
|||
|
|||
if($busqueda) { |
|||
$marcas = Marca::where('nombre', 'LIKE', "%{$busqueda}%")->get(); |
|||
|
|||
if($marcas->count() == 0) { |
|||
return redirect()->route('marca.index') |
|||
->with('error', 'No existe ninguna marca con el nombre "' . $busqueda . '". Por favor, inténtalo de nuevo.'); |
|||
} |
|||
|
|||
// Si solo hay una marca, mostrar sus detalles |
|||
if($marcas->count() == 1) { |
|||
$marca = $marcas->first(); |
|||
return redirect()->route('marca.edit', $marca->id); |
|||
} |
|||
|
|||
// Si hay múltiples coincidencias, mostrar la lista filtrada |
|||
return view('marca', ["marcas" => $marcas]); |
|||
} |
|||
|
|||
// Si no hay búsqueda, mostrar todas las marcas |
|||
$marcas = Marca::all(); |
|||
return view('marcas', ["marcas" => $marcas]); |
|||
} |
|||
|
|||
/** |
|||
* Show the form for creating a new resource. |
|||
*/ |
|||
public function create() |
|||
{ |
|||
$marcas = Marca::all(); |
|||
return view('marcasCrearEditar',['marcas'=>$marcas]); |
|||
} |
|||
|
|||
/** |
|||
* Store a newly created resource in storage. |
|||
*/ |
|||
public function store(Request $request) |
|||
{ |
|||
$marca = new Marca($request->all()); |
|||
$marca->save(); |
|||
return redirect()->route('marca.index')->with('success', 'Marca creada exitosamente.'); |
|||
} |
|||
|
|||
/** |
|||
* Display the specified resource. |
|||
*/ |
|||
public function show(Marca $marca) |
|||
{ |
|||
// |
|||
} |
|||
|
|||
/** |
|||
* Show the form for editing the specified resource. |
|||
*/ |
|||
public function edit($id) |
|||
{ |
|||
$marca = Marca::find($id); |
|||
return view('marcasCrearEditar',['marca'=>$marca]); |
|||
} |
|||
|
|||
/** |
|||
* Update the specified resource in storage. |
|||
*/ |
|||
public function update(Request $request, $id) |
|||
{ |
|||
$marca = Marca::find($id); |
|||
$marca->fill($request->all()); |
|||
$marca->save(); |
|||
return redirect()->route('marca.index'); |
|||
} |
|||
|
|||
/** |
|||
* Remove the specified resource from storage. |
|||
*/ |
|||
public function destroy($id ) |
|||
{ |
|||
$marca = Marca::find($id); |
|||
$marca->delete(); |
|||
return redirect()->route('marca.index')->with('success', 'Marca eliminada exitosamente.'); |
|||
|
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
<?php |
|||
|
|||
namespace App\Models; |
|||
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
class Marca extends Model |
|||
{ |
|||
use HasFactory; |
|||
|
|||
protected $table = 'marcas'; |
|||
|
|||
protected $fillable = ['nombre']; |
|||
} |
@ -0,0 +1,23 @@ |
|||
<?php |
|||
|
|||
namespace Database\Factories; |
|||
|
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
|
|||
/** |
|||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Marca> |
|||
*/ |
|||
class MarcaFactory extends Factory |
|||
{ |
|||
/** |
|||
* Define the model's default state. |
|||
* |
|||
* @return array<string, mixed> |
|||
*/ |
|||
public function definition(): array |
|||
{ |
|||
return [ |
|||
// |
|||
]; |
|||
} |
|||
} |
@ -0,0 +1,28 @@ |
|||
<?php |
|||
|
|||
use Illuminate\Database\Migrations\Migration; |
|||
use Illuminate\Database\Schema\Blueprint; |
|||
use Illuminate\Support\Facades\Schema; |
|||
|
|||
return new class extends Migration |
|||
{ |
|||
/** |
|||
* Run the migrations. |
|||
*/ |
|||
public function up(): void |
|||
{ |
|||
Schema::create('marcas', function (Blueprint $table) { |
|||
$table->id(); |
|||
$table->string('nombre'); |
|||
$table->timestamps(); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Reverse the migrations. |
|||
*/ |
|||
public function down(): void |
|||
{ |
|||
Schema::dropIfExists('marcas'); |
|||
} |
|||
}; |
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace Database\Seeders; |
|||
|
|||
use Illuminate\Database\Console\Seeds\WithoutModelEvents; |
|||
use Illuminate\Database\Seeder; |
|||
|
|||
class MarcaSeeder extends Seeder |
|||
{ |
|||
/** |
|||
* Run the database seeds. |
|||
*/ |
|||
public function run(): void |
|||
{ |
|||
// |
|||
} |
|||
} |
@ -0,0 +1,134 @@ |
|||
@extends('layouts.dashboard') |
|||
|
|||
@section('content') |
|||
<div class="container mx-auto px-4 py-6"> |
|||
<!-- Encabezado --> |
|||
@if(session('success')) |
|||
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert"> |
|||
<span class="block sm:inline">{{ session('success') }}</span> |
|||
</div> |
|||
@endif |
|||
|
|||
@if(session('error')) |
|||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert"> |
|||
<span class="block sm:inline">{{ session('error') }}</span> |
|||
</div> |
|||
@endif |
|||
|
|||
<div class="bg-white rounded-lg shadow-lg"> |
|||
<div class="p-4 border-b border-gray-200 flex justify-between items-center"> |
|||
<h2 class="text-2xl font-bold">Gestión de Marcas</h2> |
|||
<a href="{{ route('marca.create') }}" |
|||
class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 flex items-center gap-2"> |
|||
<i class="fas fa-plus"></i> |
|||
Agregar |
|||
</a> |
|||
</div> |
|||
|
|||
<!-- Barra de búsqueda --> |
|||
<div class="p-4 border-b border-gray-200 bg-gray-50"> |
|||
<form action="{{ route('marca.index') }}" method="GET" class="flex gap-2"> |
|||
<div class="relative w-full sm:w-64"> |
|||
<input type="text" |
|||
name="busqueda" |
|||
placeholder="Buscar marca..." |
|||
value="{{ request('busqueda') }}" |
|||
class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> |
|||
<div class="absolute left-3 top-2.5 text-gray-400"> |
|||
<i class="fas fa-search"></i> |
|||
</div> |
|||
</div> |
|||
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600"> |
|||
Buscar/Actualizar |
|||
</button> |
|||
@if(request('busqueda')) |
|||
<a href="{{ route('marca.index') }}" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600"> |
|||
Limpiar |
|||
</a> |
|||
@endif |
|||
</form> |
|||
</div> |
|||
|
|||
<div class="overflow-x-auto"> |
|||
|
|||
<table class="min-w-full divide-y divide-gray-200"> |
|||
<thead class="bg-gray-50"> |
|||
<tr> |
|||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th> |
|||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Marca</th> |
|||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Acciones</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody class="bg-white divide-y divide-gray-200"> |
|||
@foreach($marcas as $marca) |
|||
<tr class="hover:bg-gray-50"> |
|||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $marca->id }}</td> |
|||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> |
|||
<i class="fas fa-car text-blue-500 mr-2"></i> |
|||
{{ $marca->nombre }} |
|||
</td> |
|||
<td class="px-6 py-4 whitespace-nowrap text-sm"> |
|||
<div class="flex gap-2"> |
|||
<a href="#" |
|||
onclick="confirmarEdicion('{{ route('marca.edit', $marca->id) }}')" |
|||
class="text-blue-600 hover:text-blue-900"> |
|||
<i class="fas fa-edit"></i> |
|||
</a> |
|||
<form action="{{ route('marca.destroy', $marca->id) }}" |
|||
method="POST" |
|||
class="inline" |
|||
onsubmit="return false;"> |
|||
@csrf |
|||
@method('DELETE') |
|||
<button type="button" |
|||
onclick="confirmarEliminacion(this)" |
|||
class="text-red-600 hover:text-red-900"> |
|||
<i class="fas fa-trash"></i> |
|||
</button> |
|||
</form> |
|||
</div> |
|||
</td> |
|||
</tr> |
|||
@endforeach |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
function confirmarEdicion(url) { |
|||
Swal.fire({ |
|||
title: '¿Editar marca?', |
|||
text: "¿Estás seguro de que deseas editar esta marca?", |
|||
icon: 'question', |
|||
showCancelButton: true, |
|||
confirmButtonColor: '#3085d6', |
|||
cancelButtonColor: '#d33', |
|||
confirmButtonText: 'Sí, editar', |
|||
cancelButtonText: 'Cancelar' |
|||
}).then((result) => { |
|||
if (result.isConfirmed) { |
|||
window.location.href = url; |
|||
} |
|||
}); |
|||
} |
|||
function confirmarEliminacion(button) { |
|||
Swal.fire({ |
|||
title: '¿Estás seguro?', |
|||
text: "Esta acción no se puede deshacer", |
|||
icon: 'warning', |
|||
showCancelButton: true, |
|||
confirmButtonColor: '#3085d6', |
|||
cancelButtonColor: '#d33', |
|||
confirmButtonText: 'Sí, eliminar', |
|||
cancelButtonText: 'Cancelar' |
|||
}).then((result) => { |
|||
if (result.isConfirmed) { |
|||
button.closest('form').onsubmit = null; |
|||
button.closest('form').submit(); |
|||
} |
|||
}); |
|||
} |
|||
</script> |
|||
@endsection |
@ -0,0 +1,132 @@ |
|||
@extends('layouts.dashboard') |
|||
|
|||
@section('content') |
|||
<div class="container mx-auto px-4 py-6"> |
|||
<div class="max-w-lg mx-auto"> |
|||
<div class="bg-white rounded-lg shadow-lg overflow-hidden"> |
|||
<div class="p-6"> |
|||
<!-- Encabezado del formulario --> |
|||
<div class="flex items-center justify-between mb-6"> |
|||
<h2 class="text-2xl font-bold text-gray-800"> |
|||
{{ isset($marca) ? 'Editar Marca' : 'Nueva Marca' }} |
|||
</h2> |
|||
<div class="h-10 w-10 bg-blue-100 rounded-full flex items-center justify-center"> |
|||
<i class="fas fa-car text-blue-600"></i> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Mensajes de error --> |
|||
@if($errors->any()) |
|||
<div class="mb-6 bg-red-50 border-l-4 border-red-500 p-4 rounded-r-lg"> |
|||
<div class="flex items-center"> |
|||
<i class="fas fa-exclamation-circle text-red-500 mr-3"></i> |
|||
<div class="text-red-700"> |
|||
<ul> |
|||
@foreach($errors->all() as $error) |
|||
<li>{{ $error }}</li> |
|||
@endforeach |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@endif |
|||
|
|||
<!-- Formulario --> |
|||
<form id="marcaForm" |
|||
action="{{ isset($marca) ? route('marca.update', $marca->id) : route('marca.store') }}" |
|||
method="POST"> |
|||
@csrf |
|||
@if(isset($marca)) |
|||
@method('PUT') |
|||
@endif |
|||
|
|||
<div class="space-y-6"> |
|||
<!-- Campo Nombre --> |
|||
<div> |
|||
<label for="nombre" class="block text-sm font-medium text-gray-700 mb-2"> |
|||
Nombre de la Marca |
|||
</label> |
|||
<div class="relative rounded-md shadow-sm"> |
|||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> |
|||
<i class="fas fa-tag text-gray-400"></i> |
|||
</div> |
|||
<input type="text" |
|||
name="nombre" |
|||
id="nombre" |
|||
class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" |
|||
value="{{ isset($marca) ? $marca->nombre : old('nombre') }}" |
|||
placeholder="Ingrese el nombre de la marca" |
|||
required> |
|||
</div> |
|||
@error('nombre') |
|||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p> |
|||
@enderror |
|||
</div> |
|||
|
|||
<!-- Botones de acción --> |
|||
<div class="flex justify-end space-x-2 pt-4 border-t border-gray-200"> |
|||
<a href="{{ route('marca.index') }}" |
|||
class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> |
|||
Cancelar |
|||
</a> |
|||
<button type="button" |
|||
onclick="confirmarAccion()" |
|||
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> |
|||
{{ isset($marca) ? 'Actualizar' : 'Guardar' }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
function confirmarAccion() { |
|||
const esEdicion = {{ isset($marca) ? 'true' : 'false' }}; |
|||
const nombre = document.getElementById('nombre').value.trim(); |
|||
|
|||
if (!nombre) { |
|||
Swal.fire({ |
|||
title: 'Error', |
|||
text: 'El nombre de la marca es obligatorio', |
|||
icon: 'error', |
|||
confirmButtonColor: '#3085d6', |
|||
confirmButtonText: 'Entendido' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
Swal.fire({ |
|||
title: esEdicion ? '¿Editar marca?' : '¿Guardar marca?', |
|||
html: esEdicion ? |
|||
`¿Estás seguro de editar la marca a:<br><strong>${nombre}</strong>?` : |
|||
`¿Estás seguro de guardar la marca:<br><strong>${nombre}</strong>?`, |
|||
icon: 'question', |
|||
showCancelButton: true, |
|||
confirmButtonColor: '#3085d6', |
|||
cancelButtonColor: '#d33', |
|||
confirmButtonText: esEdicion ? 'Sí, editar' : 'Sí, guardar', |
|||
cancelButtonText: 'Cancelar' |
|||
}).then((result) => { |
|||
if (result.isConfirmed) { |
|||
document.getElementById('marcaForm').submit(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
// Prevenir envío del formulario con Enter |
|||
document.getElementById('marcaForm').addEventListener('keypress', function(e) { |
|||
if (e.key === 'Enter') { |
|||
e.preventDefault(); |
|||
confirmarAccion(); |
|||
} |
|||
}); |
|||
|
|||
// Focus en el campo nombre al cargar la página |
|||
document.addEventListener('DOMContentLoaded', function() { |
|||
document.getElementById('nombre').focus(); |
|||
}); |
|||
</script> |
|||
@endsection |
@ -0,0 +1,108 @@ |
|||
@extends('layouts.dashboard') |
|||
|
|||
@section('content') |
|||
<div class="container mx-auto px-4 py-6"> |
|||
<!-- Encabezado --> |
|||
@if(session('success')) |
|||
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert"> |
|||
<span class="block sm:inline">{{ session('success') }}</span> |
|||
</div> |
|||
@endif |
|||
|
|||
@if(session('error')) |
|||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert"> |
|||
<span class="block sm:inline">{{ session('error') }}</span> |
|||
</div> |
|||
@endif |
|||
|
|||
<div class="bg-white rounded-lg shadow-lg"> |
|||
<div class="p-4 border-b border-gray-200 flex justify-between items-center"> |
|||
<h2 class="text-2xl font-bold">Gestión de Usuarios</h2> |
|||
</div> |
|||
|
|||
<!-- Barra de búsqueda --> |
|||
<div class="p-4 border-b border-gray-200 bg-gray-50"> |
|||
<form action="{{ route('usuarios') }}" method="GET" class="flex gap-2"> |
|||
<div class="relative w-full sm:w-64"> |
|||
<input type="text" |
|||
name="busqueda" |
|||
placeholder="Buscar usuario..." |
|||
value="{{ request('busqueda') }}" |
|||
class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> |
|||
<div class="absolute left-3 top-2.5 text-gray-400"> |
|||
<i class="fas fa-search"></i> |
|||
</div> |
|||
</div> |
|||
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600"> |
|||
Buscar |
|||
</button> |
|||
@if(request('busqueda')) |
|||
<a href="{{ route('usuarios') }}" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600"> |
|||
Limpiar |
|||
</a> |
|||
@endif |
|||
</form> |
|||
</div> |
|||
|
|||
<div class="overflow-x-auto"> |
|||
<table class="min-w-full divide-y divide-gray-200"> |
|||
<thead class="bg-gray-50"> |
|||
<tr> |
|||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th> |
|||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Nombre</th> |
|||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th> |
|||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Acciones</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody class="bg-white divide-y divide-gray-200"> |
|||
@if($usuarios->isEmpty()) |
|||
<tr> |
|||
<td colspan="4" class="px-6 py-4 text-center text-gray-500">No hay usuarios registrados.</td> |
|||
</tr> |
|||
@else |
|||
@foreach($usuarios as $usuario) |
|||
<tr class="hover:bg-gray-50"> |
|||
<td class="px-6 py-4 whitespace-nowrap">{{ $usuario->id }}</td> |
|||
<td class="px-6 py-4 whitespace-nowrap">{{ $usuario->name }}</td> |
|||
<td class="px-6 py-4 whitespace-nowrap">{{ $usuario->email }}</td> |
|||
<td class="px-6 py-4 whitespace-nowrap"> |
|||
<div class="flex gap-2"> |
|||
<div class="flex gap-2"> |
|||
<form action="{{ route('usuarios.destroy', $usuario->id) }}" method="POST" class="inline" onsubmit="return false;"> |
|||
@csrf |
|||
@method('DELETE') |
|||
<button type="button" onclick="confirmarEliminacion(this)" class="text-red-600 hover:text-red-900"> |
|||
<i class="fas fa-trash"></i> <!-- Icono de eliminación --> |
|||
</button> |
|||
</form> |
|||
</div> |
|||
</td> |
|||
</tr> |
|||
@endforeach |
|||
@endif |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
function confirmarEliminacion(button) { |
|||
Swal.fire({ |
|||
title: '¿Estás seguro?', |
|||
text: "Esta acción no se puede deshacer", |
|||
icon: 'warning', |
|||
showCancelButton: true, |
|||
confirmButtonColor: '#3085d6', |
|||
cancelButtonColor: '#d33', |
|||
confirmButtonText: 'Sí, eliminar', |
|||
cancelButtonText: 'Cancelar' |
|||
}).then((result) => { |
|||
if (result.isConfirmed) { |
|||
button.closest('form').onsubmit = null; |
|||
button.closest('form').submit(); |
|||
} |
|||
}); |
|||
} |
|||
</script> |
|||
@endsection |
Loading…
Reference in new issue