Merge: integrar cambios del trabajo con chat en tiempo real

This commit is contained in:
2026-04-28 16:30:01 -06:00
parent 47d29b7f13
commit b469b884f5
10 changed files with 402 additions and 384 deletions
+170 -204
View File
@@ -1,247 +1,213 @@
@extends('layouts.landing')
@section('title',"Editar")
@section('title', 'Mi perfil')
@section('content')
<style>
.custom-file-upload {
display: flex;
align-items: center;
gap: 10px;
}
.custom-file-upload span {
font-size: 13px;
}
</style>
@hasrole('Alumno')
<div class="container-fluid">
{{-- Card editar grupo --}}
<div class="card shadow mb-4">
<div class="card-header py-3">
<div class="d-sm-flex align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Editar grupo</h6>
<a href="{{route('grupo.index')}}" class="d-sm-inline-block btn btn-sm btn-primary shadow-sm">
<i class="fas fa-download fa-sm text-white-50"></i> Regresar
</a>
</div>
</div>
<h6 class="m-0 font-weight-bold text-primary">Expediente</h6>
<div class="card-body">
@if (session('info'))
<div class="alert alert-success">
<strong>{{session('info')}}</strong>
</div>
@endif
<form action="{{route('grupo.update',$grupo->id)}}" method="POST">
@method('PUT')
@csrf
<div class="mb-3">
<label>Seleccionar Carrera</label>
<select class="form-control" name="plan_id">
<option value="">Seleccionar plan</option>
@foreach ($plans as $nivel => $grupos)
<optgroup label="{{ $nivel }}">
@foreach ($grupos as $plan)
<option value="{{ $plan->id }}" {{ $plan->id == $grupo->plan_id ? 'selected' : '' }}>
{{ $plan->carreraRel->name }}
({{ $plan->name }}-{{ $plan->rvoe }})
</option>
@endforeach
</optgroup>
@endforeach
</select>
</div>
<div class="mb-3">
<label>Seleccionar ciclo</label>
<select class="form-control" name="ciclo">
<option value="0">Seleccionar ciclo</option>
@for ($i=1 ; $i <= $ciclos->duracion ; $i++)
<option value="{{ $i }}" @selected($i == $grupo->ciclo)>{{$i}}</option>
@endfor
</select>
</div>
<div class="mb-3">
<label>Seleccionar turno</label>
<select class="form-control" name="turno">
<option value="0">Seleccionar turno</option>
@foreach ($turnos as $turno)
<option value="{{ $turno->id }}" {{ $turno->id == $grupo->turno ? 'selected' : '' }}>
{{$turno->name}}
</option>
@endforeach
</select>
</div>
<div class="mb-3">
<label>Seleccionar plantel</label>
<select class="form-control" name="plantel">
<option value="0">Seleccionar plantel</option>
@foreach ($planteles as $plantel)
<option value="{{ $plantel->id }}" {{ $plantel->id == $grupo->plantel ? 'selected' : '' }}>
{{$plantel->name}}
</option>
@endforeach
</select>
</div>
<div class="mb-3">
<label>Seleccionar status</label>
<select class="form-control" name="status">
<option value="1" {{ 1 == $grupo->status ? 'selected' : '' }}>Activo</option>
<option value="0" {{ 0 == $grupo->status ? 'selected' : '' }}>Inactivo</option>
</select>
</div>
<input class="btn btn-primary" type="submit" value="Guardar">
</form>
</div>
</div>
{{-- Card Materias y Docentes --}}
<div class="card shadow mb-4">
<div class="card-header py-3">
<div class="d-sm-flex align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Materias</h6>
@can('grupo.create')
<button onclick="$('#modalDocente').modal('show')"
class="d-sm-inline-block btn btn-sm btn-success shadow-sm">
<i class="fas fa-plus fa-sm text-white-50"></i> Asignar materia a docente
@hasrole('Alumno')
<button onclick="Livewire.dispatch('documentos')"
class="btn btn-sm btn-success shadow-sm">
<i class="fas fa-file fa-sm text-white-50"></i> Expediente
</button>
@endcan
@endrole
</div>
</div>
<div class="card-body">
@if (session('infogrupo'))
<div class="alert alert-success">
<strong>{{session('infogrupo')}}</strong>
</div>
@endif
<div class="container-fluid">
<table id="tcont" class="table table-striped table-bordered nowrap table-hover" style="width:100%;">
<thead>
<tr>
<th>Id</th>
<th>Ciclo</th>
<th>Nombre de la materia</th>
<th>Docente</th>
<th>Docente asignado</th>
</tr>
</thead>
<tbody>
@forelse ($grupo->plan->carreraRel->carreraMaterial as $material)
@php
$docenteAsignado = $grupo->docentes->firstWhere('pivot.materia_id', $material->id);
$usr = $docenteAsignado?->docentes->first();
@endphp
<tr>
<td>{{ $material->id }}</td>
<td>{{ $material->ciclo }}</td>
<td>{{ $material->name }}</td>
<td>{{ $usr?->name }} {{ $usr?->apellidoPaterno ?? 'Sin docente' }}</td>
<td>
@if($docenteAsignado)
@can('grupo.destroy')
<form class="delete-form"
action="{{route('grupo.destroy',$grupo->id)}}"
method="POST">
@csrf
@method('DELETE')
<input class="d-none" name="docente" value="{{$docenteAsignado->id}}">
<button type="submit" style="border:none; background:none;">
<i class="fa-solid fa-circle-xmark fa-xl" style="color:#e66565;"></i>
</button>
</form>
@endcan
@endif
</td>
</tr>
@empty
<tr><td colspan="5">Sin materias en este plan.</td></tr>
@endforelse
</tbody>
</table>
</div>
<livewire:grupo-docente :grupo="$grupo"/>
<livewire:documentos/>
</div>
</div>
{{-- Card Alumnos --}}
</div>
@endrole
<div class="container-fluid">
<div class="card shadow mb-4">
<div class="card-header py-3">
<div class="d-sm-flex align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Alumnos</h6>
@can('grupo.create')
<button onclick="Livewire.dispatch('create-grupo')"
class="d-sm-inline-block btn btn-sm btn-success shadow-sm">
<i class="fas fa-plus fa-sm text-white-50"></i> Agregar alumno
</button>
@endcan
<h6 class="m-0 font-weight-bold text-primary">Mis Datos</h6>
</div>
</div>
<div class="card-body">
<div class="container-fluid">
<table id="tcont2" class="table table-striped table-bordered nowrap table-hover" style="width:100%;">
<thead>
<tr>
<th>Id</th>
<th>Nombre</th>
<th>Opciones</th>
</tr>
</thead>
<tbody>
@forelse ($grupo->alumnos as $alumno)
<tr>
<td>{{$alumno->id}}</td>
<td>
{{$alumno->usuario->first()?->name}}
{{$alumno->usuario->first()?->apellidoPaterno}}
{{$alumno->usuario->first()?->apellidoMaterno}}
</td>
<td>
@can('grupo.destroy')
<form class="delete-form"
action="{{route('grupo.destroy',$grupo->id)}}"
method="POST">
@csrf
@method('DELETE')
<input class="d-none" name="alumno" value="{{$alumno->id}}">
<button type="submit" style="border:none; background:none;">
<i class="fa-solid fa-circle-xmark fa-xl" style="color:#e66565;"></i>
</button>
</form>
@endcan
</td>
</tr>
@empty
<tr><td colspan="3">Sin alumnos.</td></tr>
@endforelse
</tbody>
</table>
</div>
<livewire:grupo-alumno :grupo="$grupo"/>
@livewire('profile.update-profile-information-form')
</div>
</div>
</div>
<div class="container-fluid">
<div class="card shadow mb-4">
<div class="card-header py-3">
<div class="d-sm-flex align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Contraseña</h6>
</div>
</div>
<div class="card-body">
@livewire('profile.update-password-form')
</div>
</div>
</div>
<div class="container-fluid">
<div class="card shadow mb-4">
<div class="card-header py-3">
<div class="d-sm-flex align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Sesiones activas</h6>
</div>
</div>
<div class="card-body">
@livewire('profile.logout-other-browser-sessions-form')
</div>
</div>
</div>
<div class="modal fade" id="visorModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Vista previa</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<iframe id="visorFrame" width="100%" height="600px" style="border:none;"></iframe>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
@include('layouts._partials.tablaScript')
@include('layouts._partials.delete')
<script>
document.addEventListener('livewire:init', () => {
// Modal agregar alumno
Livewire.on('open-grupo-modal', () => {
$('#exampleModal').modal('show');
});
Livewire.on('close-modal', () => {
$('#exampleModal').modal('hide');
document.addEventListener('livewire:init', () => {
Livewire.on('open-documentos-modal', () => {
$('#exampleModal').modal('show');
});
Livewire.on('saved', (event) => {
const msgs = {
profile: { title: '¡Guardado!', text: 'Tu perfil ha sido actualizado.' },
password: { title: '¡Contraseña actualizada!', text: 'Tu contraseña ha sido cambiada correctamente.' },
};
const msg = msgs[event[0]?.component] || { title: '¡Guardado!', text: 'Los cambios han sido guardados.' };
Swal.fire({
icon: 'success',
title: msg.title,
text: msg.text,
timer: 2500,
showConfirmButton: false,
});
});
Livewire.on('loggedOut', () => {
$('#sesionesModal').modal('hide');
Swal.fire({
icon: 'success',
title: '¡Listo!',
text: 'Se cerraron las otras sesiones correctamente.',
timer: 2500,
showConfirmButton: false,
});
});
Livewire.on('photo-updated', () => {
Swal.fire({
icon: 'success',
title: '¡Foto actualizada!',
text: 'Tu foto de perfil ha sido actualizada.',
timer: 2500,
showConfirmButton: false,
});
});
});
// Modal agregar docente
Livewire.on('open-modal-docente', () => {
$('#modalDocente').modal('show');
function verDocumento(url) {
document.getElementById('visorFrame').src = url + '?t=' + new Date().getTime();
var modal = new bootstrap.Modal(document.getElementById('visorModal'));
modal.show();
}
// 🔥 limpiar iframe al cerrar
document.getElementById('visorModal').addEventListener('hidden.bs.modal', function () {
document.getElementById('visorFrame').src = '';
});
Livewire.on('close-modal-docente', () => {
$('#modalDocente').modal('hide');
</script>
<script>
function updateFileName(input, targetId) {
const fileName = input.files[0]?.name || 'Ningún archivo seleccionado';
document.getElementById(targetId).textContent = fileName;
}
</script>
<script>
Livewire.on('saved', () => {
Swal.fire({
icon: 'success',
title: '¡Guardado!',
text: 'Tu perfil ha sido actualizado correctamente.',
timer: 2500,
showConfirmButton: false,
});
});
Livewire.on('photo-updated', () => {
Swal.fire({
icon: 'success',
title: '¡Foto actualizada!',
text: 'Tu foto de perfil ha sido actualizada.',
timer: 2500,
showConfirmButton: false,
});
});
</script>