Merge: integrar cambios del trabajo con chat en tiempo real
This commit is contained in:
@@ -19,6 +19,8 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
||||
{
|
||||
Validator::make($input, [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'apellidoPaterno' => ['nullable', 'string', 'max:255'],
|
||||
'apellidoMaterno' => ['nullable', 'string', 'max:255'],
|
||||
'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)],
|
||||
'photo' => ['nullable', 'mimes:jpg,jpeg,png', 'max:1024'],
|
||||
])->validateWithBag('updateProfileInformation');
|
||||
@@ -33,6 +35,8 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
||||
} else {
|
||||
$user->forceFill([
|
||||
'name' => $input['name'],
|
||||
'apellidoPaterno' => $input['apellidoPaterno'],
|
||||
'apellidoMaterno' => $input['apellidoMaterno'],
|
||||
'email' => $input['email'],
|
||||
])->save();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ class User extends Authenticatable
|
||||
use Notifiable;
|
||||
use TwoFactorAuthenticatable;
|
||||
use HasRoles;
|
||||
use HasProfilePhoto;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
|
||||
@@ -386,3 +386,4 @@ transform:translateY(0);
|
||||
}
|
||||
|
||||
/* carrusel */
|
||||
|
||||
|
||||
@@ -146,7 +146,13 @@
|
||||
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="mr-2 d-none d-lg-inline text-gray-600 small">{{ Auth::user()->name }}</span>
|
||||
<<<<<<< Updated upstream
|
||||
<img class="img-profile rounded-circle" src="{{ Auth::user()->profile_photo_url }}">
|
||||
=======
|
||||
{{-- <img class="img-profile rounded-circle"
|
||||
src="{{ Auth::user()->profile_photo_url }}"
|
||||
alt="{{ Auth::user()->name }}"> --}}
|
||||
>>>>>>> Stashed changes
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in"
|
||||
aria-labelledby="userDropdown">
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
<!-- Sidebar - Brand -->
|
||||
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="">
|
||||
<div class="sidebar-brand-icon">
|
||||
<img src="https://1000marcas.net/wp-content/uploads/2020/03/logo-Xbox.png" alt="SECUIEP Logo" style="width: 40px; height: auto;">
|
||||
<img src="https://alumnos.sistemasecuiep.com/logo.png" alt="SECUIEP Logo" style="width: 100px; height: auto;">
|
||||
</div>
|
||||
<div class="sidebar-brand-text mx-3">SECUIEP</div>
|
||||
</a>
|
||||
<!-- Divider -->
|
||||
<hr class="sidebar-divider my-0">
|
||||
|
||||
@@ -1,98 +1,99 @@
|
||||
<x-action-section>
|
||||
<x-slot name="title">
|
||||
{{ __('Browser Sessions') }}
|
||||
</x-slot>
|
||||
<div x-data="{
|
||||
init() {
|
||||
Livewire.on('confirming-logout-other-browser-sessions', () => {
|
||||
$('#sesionesModal').modal('show');
|
||||
});
|
||||
}
|
||||
}">
|
||||
<x-action-section>
|
||||
<x-slot name="title"></x-slot>
|
||||
<x-slot name="description"></x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
{{ __('Manage and log out your active sessions on other browsers and devices.') }}
|
||||
</x-slot>
|
||||
<x-slot name="content">
|
||||
|
||||
<x-slot name="content">
|
||||
<div class="max-w-xl text-sm text-gray-600">
|
||||
{{ __('If necessary, you may log out of all of your other browser sessions across all of your devices. Some of your recent sessions are listed below; however, this list may not be exhaustive. If you feel your account has been compromised, you should also update your password.') }}
|
||||
</div>
|
||||
<p class="text-muted small mb-4">
|
||||
Si es necesario, puedes cerrar sesión en todos los demás dispositivos. Si crees que tu cuenta fue comprometida, también deberías actualizar tu contraseña.
|
||||
</p>
|
||||
|
||||
@if (count($this->sessions) > 0)
|
||||
<div class="mt-5 space-y-6">
|
||||
<!-- Other Browser Sessions -->
|
||||
@foreach ($this->sessions as $session)
|
||||
<div class="flex items-center">
|
||||
<div>
|
||||
@if ($session->agent->isDesktop())
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-8 text-gray-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25m18 0A2.25 2.25 0 0018.75 3H5.25A2.25 2.25 0 003 5.25m18 0V12a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 12V5.25" />
|
||||
</svg>
|
||||
@else
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-8 text-gray-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 1.5H8.25A2.25 2.25 0 006 3.75v16.5a2.25 2.25 0 002.25 2.25h7.5A2.25 2.25 0 0018 20.25V3.75a2.25 2.25 0 00-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3" />
|
||||
</svg>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="ms-3">
|
||||
<div class="text-sm text-gray-600">
|
||||
{{ $session->agent->platform() ? $session->agent->platform() : __('Unknown') }} - {{ $session->agent->browser() ? $session->agent->browser() : __('Unknown') }}
|
||||
@if (count($this->sessions) > 0)
|
||||
<div class="mb-4">
|
||||
@foreach ($this->sessions as $session)
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="mr-3 text-secondary">
|
||||
@if ($session->agent->isDesktop())
|
||||
<i class="fas fa-desktop fa-2x"></i>
|
||||
@else
|
||||
<i class="fas fa-mobile-alt fa-2x"></i>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-xs text-gray-500">
|
||||
<div class="font-weight-bold small">
|
||||
{{ $session->agent->platform() ?: 'Desconocido' }}
|
||||
—
|
||||
{{ $session->agent->browser() ?: 'Desconocido' }}
|
||||
</div>
|
||||
<div class="text-muted small">
|
||||
{{ $session->ip_address }},
|
||||
|
||||
@if ($session->is_current_device)
|
||||
<span class="text-green-500 font-semibold">{{ __('This device') }}</span>
|
||||
<span class="text-success font-weight-bold">Este dispositivo</span>
|
||||
@else
|
||||
{{ __('Last active') }} {{ $session->last_active }}
|
||||
Última actividad: {{ $session->last_active }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex items-center mt-5">
|
||||
<x-button wire:click="confirmLogout" wire:loading.attr="disabled">
|
||||
{{ __('Log Out Other Browser Sessions') }}
|
||||
</x-button>
|
||||
<button class="btn btn-danger"
|
||||
wire:click="confirmLogout"
|
||||
wire:loading.attr="disabled">
|
||||
<span wire:loading class="spinner-border spinner-border-sm mr-1" role="status"></span>
|
||||
<i class="fas fa-sign-out-alt mr-1"></i>
|
||||
Cerrar otras sesiones
|
||||
</button>
|
||||
|
||||
<x-action-message class="ms-3" on="loggedOut">
|
||||
{{ __('Done.') }}
|
||||
</x-action-message>
|
||||
</div>
|
||||
|
||||
<!-- Log Out Other Devices Confirmation Modal -->
|
||||
<x-dialog-modal wire:model.live="confirmingLogout">
|
||||
<x-slot name="title">
|
||||
{{ __('Log Out Other Browser Sessions') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
{{ __('Please enter your password to confirm you would like to log out of your other browser sessions across all of your devices.') }}
|
||||
|
||||
<div class="mt-4" x-data="{}" x-on:confirming-logout-other-browser-sessions.window="setTimeout(() => $refs.password.focus(), 250)">
|
||||
<x-input type="password" class="mt-1 block w-3/4"
|
||||
autocomplete="current-password"
|
||||
placeholder="{{ __('Password') }}"
|
||||
x-ref="password"
|
||||
wire:model="password"
|
||||
wire:keydown.enter="logoutOtherBrowserSessions" />
|
||||
</x-slot>
|
||||
</x-action-section>
|
||||
|
||||
<!-- Modal Bootstrap -->
|
||||
<div class="modal fade" id="sesionesModal" tabindex="-1" role="dialog"
|
||||
wire:ignore>
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Cerrar otras sesiones</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="text-muted small mb-3">
|
||||
Ingresa tu contraseña para confirmar que deseas cerrar sesión en los demás dispositivos.
|
||||
</p>
|
||||
<input type="password"
|
||||
class="form-control"
|
||||
placeholder="Contraseña"
|
||||
autocomplete="current-password"
|
||||
wire:model="password"
|
||||
wire:keydown.enter="logoutOtherBrowserSessions" />
|
||||
<x-input-error for="password" class="mt-2" />
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="footer">
|
||||
<x-secondary-button wire:click="$toggle('confirmingLogout')" wire:loading.attr="disabled">
|
||||
{{ __('Cancel') }}
|
||||
</x-secondary-button>
|
||||
|
||||
<x-button class="ms-3"
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary"
|
||||
data-dismiss="modal">
|
||||
Cancelar
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger"
|
||||
wire:click="logoutOtherBrowserSessions"
|
||||
wire:loading.attr="disabled">
|
||||
{{ __('Log Out Other Browser Sessions') }}
|
||||
</x-button>
|
||||
</x-slot>
|
||||
</x-dialog-modal>
|
||||
</x-slot>
|
||||
</x-action-section>
|
||||
<span wire:loading class="spinner-border spinner-border-sm mr-1" role="status"></span>
|
||||
Confirmar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -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">×</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>
|
||||
|
||||
@@ -1,39 +1,37 @@
|
||||
<x-form-section submit="updatePassword">
|
||||
<x-slot name="title">
|
||||
{{ __('Update Password') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
{{ __('Ensure your account is using a long, random password to stay secure.') }}
|
||||
</x-slot>
|
||||
<x-slot name="title"></x-slot>
|
||||
<x-slot name="description"></x-slot>
|
||||
|
||||
<x-slot name="form">
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<x-label for="current_password" value="{{ __('Current Password') }}" />
|
||||
<x-input id="current_password" type="password" class="mt-1 block w-full" wire:model="state.current_password" autocomplete="current-password" />
|
||||
<x-input-error for="current_password" class="mt-2" />
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label for="current_password" class="form-label fw-bold">Contraseña actual</label>
|
||||
<input id="current_password" type="password" class="form-control"
|
||||
wire:model="state.current_password" autocomplete="current-password" />
|
||||
<x-input-error for="current_password" class="mt-1" />
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<x-label for="password" value="{{ __('New Password') }}" />
|
||||
<x-input id="password" type="password" class="mt-1 block w-full" wire:model="state.password" autocomplete="new-password" />
|
||||
<x-input-error for="password" class="mt-2" />
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label for="password" class="form-label fw-bold">Nueva contraseña</label>
|
||||
<input id="password" type="password" class="form-control"
|
||||
wire:model="state.password" autocomplete="new-password" />
|
||||
<x-input-error for="password" class="mt-1" />
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<x-label for="password_confirmation" value="{{ __('Confirm Password') }}" />
|
||||
<x-input id="password_confirmation" type="password" class="mt-1 block w-full" wire:model="state.password_confirmation" autocomplete="new-password" />
|
||||
<x-input-error for="password_confirmation" class="mt-2" />
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label for="password_confirmation" class="form-label fw-bold">Confirmar contraseña</label>
|
||||
<input id="password_confirmation" type="password" class="form-control"
|
||||
wire:model="state.password_confirmation" autocomplete="new-password" />
|
||||
<x-input-error for="password_confirmation" class="mt-1" />
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="actions">
|
||||
<x-action-message class="me-3" on="saved">
|
||||
{{ __('Saved.') }}
|
||||
</x-action-message>
|
||||
|
||||
<x-button>
|
||||
{{ __('Save') }}
|
||||
</x-button>
|
||||
<button type="submit" class="btn btn-primary"
|
||||
wire:loading.attr="disabled">
|
||||
<span wire:loading
|
||||
class="spinner-border spinner-border-sm mr-1"
|
||||
role="status" aria-hidden="true"></span>
|
||||
Guardar
|
||||
</button>
|
||||
</x-slot>
|
||||
</x-form-section>
|
||||
|
||||
@@ -1,95 +1,137 @@
|
||||
<x-form-section submit="updateProfileInformation">
|
||||
<x-slot name="title">
|
||||
{{ __('Profile Information') }}
|
||||
{{ __('Información de perfil') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
{{ __('Update your account\'s profile information and email address.') }}
|
||||
{{ __('Actualice la información de su cuenta y dirección de correo electrónico.') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="form">
|
||||
<!-- Profile Photo -->
|
||||
@if (Laravel\Jetstream\Jetstream::managesProfilePhotos())
|
||||
<div x-data="{photoName: null, photoPreview: null}" class="col-span-6 sm:col-span-4">
|
||||
<!-- Profile Photo File Input -->
|
||||
<input type="file" id="photo" class="hidden"
|
||||
wire:model.live="photo"
|
||||
x-ref="photo"
|
||||
x-on:change="
|
||||
photoName = $refs.photo.files[0].name;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
photoPreview = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL($refs.photo.files[0]);
|
||||
" />
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
|
||||
<x-label for="photo" value="{{ __('Photo') }}" />
|
||||
|
||||
<!-- Current Profile Photo -->
|
||||
<div class="mt-2" x-show="! photoPreview">
|
||||
<img src="{{ $this->user->profile_photo_url }}" alt="{{ $this->user->name }}" class="rounded-full size-20 object-cover">
|
||||
|
||||
<!-- Columna derecha: Nombre y correo -->
|
||||
<div class="col-12 col-md-8">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label fw-bold">Nombre</label>
|
||||
<input id="name" type="text" class="form-control"
|
||||
wire:model="state.name" required autocomplete="name" />
|
||||
<x-input-error for="name" class="mt-1" />
|
||||
</div>
|
||||
|
||||
<div class=" mb-3">
|
||||
<label for="apellidoPaterno" class="form-label fw-bold">Apellido paterno</label>
|
||||
<input id="apellidoPaterno" type="text" class="form-control"
|
||||
wire:model="state.apellidoPaterno" autocomplete="off" />
|
||||
<x-input-error for="apellidoPaterno" class="mt-1" />
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="apellidoMaterno" class="form-label fw-bold">Apellido materno</label>
|
||||
<input id="apellidoMaterno" type="text" class="form-control"
|
||||
wire:model="state.apellidoMaterno" autocomplete="off" />
|
||||
<x-input-error for="apellidoMaterno" class="mt-1" />
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label fw-bold">Correo electrónico</label>
|
||||
<input id="email" type="email" class="form-control"
|
||||
wire:model="state.email" required autocomplete="username" />
|
||||
<x-input-error for="email" class="mt-1" />
|
||||
|
||||
@if (Laravel\Fortify\Features::enabled(Laravel\Fortify\Features::emailVerification()) && ! $this->user->hasVerifiedEmail())
|
||||
<p class="text-muted small mt-2">
|
||||
Tu dirección de correo no está verificada.
|
||||
<button type="button" class="btn btn-link btn-sm p-0"
|
||||
wire:click.prevent="sendEmailVerification">
|
||||
Reenviar verificación
|
||||
</button>
|
||||
</p>
|
||||
|
||||
@if ($this->verificationLinkSent)
|
||||
<p class="text-success small mt-1">
|
||||
<i class="fas fa-check mr-1"></i>
|
||||
Se envió un nuevo enlace de verificación a tu correo.
|
||||
</p>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- New Profile Photo Preview -->
|
||||
<div class="mt-2" x-show="photoPreview" style="display: none;">
|
||||
<span class="block rounded-full size-20 bg-cover bg-no-repeat bg-center"
|
||||
x-bind:style="'background-image: url(\'' + photoPreview + '\');'">
|
||||
</span>
|
||||
|
||||
<!-- Columna izquierda: Foto -->
|
||||
@if (Laravel\Jetstream\Jetstream::managesProfilePhotos())
|
||||
<div x-data="{photoName: null, photoPreview: null}" class="col-12 col-md-4 d-flex flex-column align-items-center mb-4">
|
||||
|
||||
<input type="file" id="photo" class="d-none"
|
||||
wire:model.live="photo"
|
||||
x-ref="photo"
|
||||
x-on:change="
|
||||
photoName = $refs.photo.files[0].name;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => { photoPreview = e.target.result; };
|
||||
reader.readAsDataURL($refs.photo.files[0]);
|
||||
" />
|
||||
|
||||
<label class="form-label fw-bold mb-3">Foto de perfil</label>
|
||||
|
||||
<!-- Foto actual -->
|
||||
<div x-show="! photoPreview" class="mb-3">
|
||||
<img src="{{ $this->user->profile_photo_url }}"
|
||||
alt="{{ $this->user->name }}"
|
||||
class="rounded-circle border shadow-sm"
|
||||
style="width: 120px; height: 120px; object-fit: cover;">
|
||||
</div>
|
||||
|
||||
<!-- Preview nueva foto -->
|
||||
<div x-show="photoPreview" style="display: none;" class="mb-3">
|
||||
<span class="rounded-circle d-block border shadow-sm"
|
||||
x-bind:style="'background-image: url(\'' + photoPreview + '\'); width:120px; height:120px; border-radius:50%; background-size:cover; background-position:center;'">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Botones debajo de la foto -->
|
||||
<div class="d-flex flex-column align-items-center gap-2" style="width: 160px;">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary w-100"
|
||||
x-on:click.prevent="$refs.photo.click()">
|
||||
<i class="fas fa-camera mr-1"></i> Cambiar foto
|
||||
</button>
|
||||
|
||||
@if ($this->user->profile_photo_path)
|
||||
<button type="button" class="btn btn-sm btn-outline-danger w-100"
|
||||
wire:click="deleteProfilePhoto">
|
||||
<i class="fas fa-trash mr-1"></i> Eliminar foto
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<x-input-error for="photo" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<x-secondary-button class="mt-2 me-2" type="button" x-on:click.prevent="$refs.photo.click()">
|
||||
{{ __('Select A New Photo') }}
|
||||
</x-secondary-button>
|
||||
|
||||
@if ($this->user->profile_photo_path)
|
||||
<x-secondary-button type="button" class="mt-2" wire:click="deleteProfilePhoto">
|
||||
{{ __('Remove Photo') }}
|
||||
</x-secondary-button>
|
||||
@endif
|
||||
|
||||
<x-input-error for="photo" class="mt-2" />
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Name -->
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<x-label for="name" value="{{ __('Name') }}" />
|
||||
<x-input id="name" type="text" class="mt-1 block w-full" wire:model="state.name" required autocomplete="name" />
|
||||
<x-input-error for="name" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<x-label for="email" value="{{ __('Email') }}" />
|
||||
<x-input id="email" type="email" class="mt-1 block w-full" wire:model="state.email" required autocomplete="username" />
|
||||
<x-input-error for="email" class="mt-2" />
|
||||
|
||||
@if (Laravel\Fortify\Features::enabled(Laravel\Fortify\Features::emailVerification()) && ! $this->user->hasVerifiedEmail())
|
||||
<p class="text-sm mt-2">
|
||||
{{ __('Your email address is unverified.') }}
|
||||
|
||||
<button type="button" class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" wire:click.prevent="sendEmailVerification">
|
||||
{{ __('Click here to re-send the verification email.') }}
|
||||
</button>
|
||||
</p>
|
||||
|
||||
@if ($this->verificationLinkSent)
|
||||
<p class="mt-2 font-medium text-sm text-green-600">
|
||||
{{ __('A new verification link has been sent to your email address.') }}
|
||||
</p>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="actions">
|
||||
<x-action-message class="me-3" on="saved">
|
||||
{{ __('Saved.') }}
|
||||
</x-action-message>
|
||||
|
||||
<x-button wire:loading.attr="disabled" wire:target="photo">
|
||||
{{ __('Save') }}
|
||||
</x-button>
|
||||
|
||||
<button type="submit" class="btn btn-primary"
|
||||
wire:loading.attr="disabled" wire:target="photo">
|
||||
<span wire:loading wire:target="photo"
|
||||
class="spinner-border spinner-border-sm mr-1"
|
||||
role="status" aria-hidden="true"></span>
|
||||
Guardar
|
||||
</button>
|
||||
</x-slot>
|
||||
|
||||
|
||||
</x-form-section>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
@forelse ($users as $user)
|
||||
<tr style="width:100%">
|
||||
<td>{{$user->id}}</td>
|
||||
<td><a href="{{route('user.show',$user->id)}}">{{$user->name}}</a></td>
|
||||
<td><a href="{{route('user.show',$user->id)}}">{{$user->name}} {{$user->apellidoPaterno}} {{$user->apellidoMaterno}}</a></td>
|
||||
|
||||
<td>
|
||||
@forelse($user->plantelUsuarios as $plantel)
|
||||
|
||||
Reference in New Issue
Block a user