Browse Source
restringi el acceso de las funciones de administrador para aceptar prestamos y que solo se pueda hacer un nuevo prestamo y yamain
14 changed files with 326 additions and 41 deletions
@ -0,0 +1,49 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Controllers; |
||||
|
|
||||
|
use Illuminate\Http\Request; |
||||
|
use App\Models\SolicitudVehiculo; |
||||
|
|
||||
|
class SolicitudVehiculoController extends Controller |
||||
|
{ |
||||
|
public function __construct() |
||||
|
{ |
||||
|
$this->middleware(['auth', 'profesor']); |
||||
|
} |
||||
|
|
||||
|
public function index() |
||||
|
{ |
||||
|
$solicitudes = SolicitudVehiculo::where('user_id', auth()->id())->get(); |
||||
|
return view('profesor.solicitudes.index', compact('solicitudes')); |
||||
|
} |
||||
|
|
||||
|
public function create() |
||||
|
{ |
||||
|
return view('profesor.solicitudes.create'); |
||||
|
} |
||||
|
|
||||
|
public function store(Request $request) |
||||
|
{ |
||||
|
$request->validate([ |
||||
|
'fecha_solicitud' => 'required|date', |
||||
|
'hora_salida' => 'required', |
||||
|
'hora_regreso' => 'required', |
||||
|
'destino' => 'required|string', |
||||
|
'motivo' => 'required|string', |
||||
|
]); |
||||
|
|
||||
|
$solicitud = new SolicitudVehiculo(); |
||||
|
$solicitud->user_id = auth()->id(); |
||||
|
$solicitud->fecha_solicitud = $request->fecha_solicitud; |
||||
|
$solicitud->hora_salida = $request->hora_salida; |
||||
|
$solicitud->hora_regreso = $request->hora_regreso; |
||||
|
$solicitud->destino = $request->destino; |
||||
|
$solicitud->motivo = $request->motivo; |
||||
|
$solicitud->estado = 'pendiente'; |
||||
|
$solicitud->save(); |
||||
|
|
||||
|
return redirect()->route('profesor.solicitudes.index') |
||||
|
->with('success', 'Solicitud creada exitosamente'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Middleware; |
||||
|
|
||||
|
use Closure; |
||||
|
use Illuminate\Http\Request; |
||||
|
use Symfony\Component\HttpFoundation\Response; |
||||
|
|
||||
|
class CheckAdminRole |
||||
|
{ |
||||
|
public function handle(Request $request, Closure $next): Response |
||||
|
{ |
||||
|
if (!auth()->check() || auth()->user()->rol !== 'admin') { |
||||
|
return redirect('/')->with('error', 'No tienes permisos de administrador para acceder a esta sección.'); |
||||
|
} |
||||
|
|
||||
|
return $next($request); |
||||
|
} |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Middleware; |
||||
|
|
||||
|
use Closure; |
||||
|
use Illuminate\Http\Request; |
||||
|
use Symfony\Component\HttpFoundation\Response; |
||||
|
|
||||
|
class CheckProfesorRole |
||||
|
{ |
||||
|
public function handle(Request $request, Closure $next): Response |
||||
|
{ |
||||
|
if (!auth()->check() || auth()->user()->rol !== 'profesor') { |
||||
|
return redirect('/')->with('error', 'No tienes permiso para acceder a esta sección.'); |
||||
|
} |
||||
|
|
||||
|
return $next($request); |
||||
|
} |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Models; |
||||
|
|
||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
|
use Illuminate\Database\Eloquent\Model; |
||||
|
|
||||
|
class SolicitudVehiculo extends Model |
||||
|
{ |
||||
|
use HasFactory; |
||||
|
|
||||
|
protected $fillable = [ |
||||
|
'user_id', |
||||
|
'fecha_solicitud', |
||||
|
'hora_salida', |
||||
|
'hora_regreso', |
||||
|
'destino', |
||||
|
'motivo', |
||||
|
'estado' |
||||
|
]; |
||||
|
|
||||
|
public function user() |
||||
|
{ |
||||
|
return $this->belongsTo(User::class); |
||||
|
} |
||||
|
} |
@ -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 |
||||
|
{ |
||||
|
public function up(): void |
||||
|
{ |
||||
|
Schema::create('solicitud_vehiculos', function (Blueprint $table) { |
||||
|
$table->id(); |
||||
|
$table->foreignId('user_id')->constrained()->onDelete('cascade'); |
||||
|
$table->date('fecha_solicitud'); |
||||
|
$table->time('hora_salida'); |
||||
|
$table->time('hora_regreso'); |
||||
|
$table->string('destino'); |
||||
|
$table->text('motivo'); |
||||
|
$table->enum('estado', ['pendiente', 'aprobada', 'rechazada'])->default('pendiente'); |
||||
|
$table->timestamps(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public function down(): void |
||||
|
{ |
||||
|
Schema::dropIfExists('solicitud_vehiculos'); |
||||
|
} |
||||
|
}; |
@ -1,28 +0,0 @@ |
|||||
<?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::table('prestamos', function (Blueprint $table) { |
|
||||
$table->enum('estado', ['pendiente', 'aceptado', 'rechazado'])->default('pendiente')->after('chofer'); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Reverse the migrations. |
|
||||
*/ |
|
||||
public function down(): void |
|
||||
{ |
|
||||
Schema::table('prestamos', function (Blueprint $table) { |
|
||||
$table->dropColumn('estado'); |
|
||||
}); |
|
||||
} |
|
||||
}; |
|
@ -0,0 +1,22 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Database\Seeders; |
||||
|
|
||||
|
use Illuminate\Database\Seeder; |
||||
|
use App\Models\User; |
||||
|
use Illuminate\Support\Facades\Hash; |
||||
|
|
||||
|
class ProfesorSeeder extends Seeder |
||||
|
{ |
||||
|
public function run(): void |
||||
|
{ |
||||
|
User::create([ |
||||
|
'name' => 'Profesor', |
||||
|
'email' => 'profesor@profesor.com', |
||||
|
'password' => Hash::make('12345678'), |
||||
|
'rol' => 'profesor', |
||||
|
'apellido' => 'Ejemplo', |
||||
|
'telefono' => '1234567890', |
||||
|
]); |
||||
|
} |
||||
|
} |
@ -0,0 +1,78 @@ |
|||||
|
@extends('layouts.dashboard') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container mx-auto px-4 py-6"> |
||||
|
<div class="max-w-2xl mx-auto"> |
||||
|
<div class="bg-white rounded-lg shadow-lg overflow-hidden"> |
||||
|
<div class="p-6"> |
||||
|
<h2 class="text-2xl font-bold text-gray-800 mb-6">Nueva Solicitud de Vehículo</h2> |
||||
|
|
||||
|
@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"> |
||||
|
<div class="text-red-700"> |
||||
|
<ul> |
||||
|
@foreach($errors->all() as $error) |
||||
|
<li>{{ $error }}</li> |
||||
|
@endforeach |
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endif |
||||
|
|
||||
|
<form action="{{ route('profesor.solicitudes.store') }}" method="POST"> |
||||
|
@csrf |
||||
|
<div class="space-y-6"> |
||||
|
<div> |
||||
|
<label for="fecha_solicitud" class="block text-sm font-medium text-gray-700 mb-2">Fecha de Solicitud</label> |
||||
|
<input type="date" name="fecha_solicitud" id="fecha_solicitud" |
||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" |
||||
|
required> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<label for="hora_salida" class="block text-sm font-medium text-gray-700 mb-2">Hora de Salida</label> |
||||
|
<input type="time" name="hora_salida" id="hora_salida" |
||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" |
||||
|
required> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<label for="hora_regreso" class="block text-sm font-medium text-gray-700 mb-2">Hora de Regreso</label> |
||||
|
<input type="time" name="hora_regreso" id="hora_regreso" |
||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" |
||||
|
required> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<label for="destino" class="block text-sm font-medium text-gray-700 mb-2">Destino</label> |
||||
|
<input type="text" name="destino" id="destino" |
||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" |
||||
|
required> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<label for="motivo" class="block text-sm font-medium text-gray-700 mb-2">Motivo</label> |
||||
|
<textarea name="motivo" id="motivo" rows="4" |
||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" |
||||
|
required></textarea> |
||||
|
</div> |
||||
|
|
||||
|
<div class="flex justify-end space-x-4"> |
||||
|
<a href="{{ route('profesor.solicitudes.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="submit" |
||||
|
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"> |
||||
|
Enviar Solicitud |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endsection |
@ -0,0 +1,51 @@ |
|||||
|
@extends('layouts.dashboard') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container mx-auto px-4 py-6"> |
||||
|
<div class="flex justify-between items-center mb-6"> |
||||
|
<h2 class="text-2xl font-bold text-gray-800">Mis Solicitudes de Vehículo</h2> |
||||
|
<a href="{{ route('profesor.solicitudes.create') }}" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> |
||||
|
Nueva Solicitud |
||||
|
</a> |
||||
|
</div> |
||||
|
|
||||
|
@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 |
||||
|
|
||||
|
<div class="bg-white shadow-md rounded-lg overflow-hidden"> |
||||
|
<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">Fecha</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Hora Salida</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Hora Regreso</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Destino</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Estado</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody class="bg-white divide-y divide-gray-200"> |
||||
|
@foreach($solicitudes as $solicitud) |
||||
|
<tr> |
||||
|
<td class="px-6 py-4 whitespace-nowrap">{{ $solicitud->fecha_solicitud }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap">{{ $solicitud->hora_salida }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap">{{ $solicitud->hora_regreso }}</td> |
||||
|
<td class="px-6 py-4">{{ $solicitud->destino }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap"> |
||||
|
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full |
||||
|
@if($solicitud->estado === 'aprobada') bg-green-100 text-green-800 |
||||
|
@elseif($solicitud->estado === 'rechazada') bg-red-100 text-red-800 |
||||
|
@else bg-yellow-100 text-yellow-800 |
||||
|
@endif"> |
||||
|
{{ ucfirst($solicitud->estado) }} |
||||
|
</span> |
||||
|
</td> |
||||
|
</tr> |
||||
|
@endforeach |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endsection |
Loading…
Reference in new issue