<?php
if (!defined('ABSPATH')) {
exit;
}
// Obtener estudiantes PRIMERO
global $wpdb;
$table_students = $wpdb->prefix . 'wes_students';
// Construir consulta con filtros
$where_conditions = array("deleted_at IS NULL");
$where_values = array();
// Filtro de búsqueda
if (isset($_GET['search']) && !empty($_GET['search'])) {
$search_term = sanitize_text_field($_GET['search']);
$where_conditions[] = "(first_name LIKE %s OR last_name LIKE %s OR email LIKE %s OR student_id LIKE %s)";
$search_like = '%' . $wpdb->esc_like($search_term) . '%';
$where_values = array_merge($where_values, array($search_like, $search_like, $search_like, $search_like));
}
// Filtro de estado
if (isset($_GET['status']) && !empty($_GET['status'])) {
$status = sanitize_text_field($_GET['status']);
$where_conditions[] = "status = %s";
$where_values[] = $status;
}
$where_clause = 'WHERE ' . implode(' AND ', $where_conditions);
if (!empty($where_values)) {
$students = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table_students $where_clause ORDER BY created_at DESC",
$where_values
));
} else {
$students = $wpdb->get_results("SELECT * FROM $table_students $where_clause ORDER BY created_at DESC");
}
// Calcular estadísticas DESPUÉS de obtener los datos
$total_students = count($students);
$active_students = array_filter($students, function($s) { return $s->status == 'active'; });
$new_students = array_filter($students, function($s) {
return strtotime($s->created_at) > strtotime('-30 days');
});
?>
<!-- CSS PROFESIONAL INTEGRADO -->
<style>
/* =================================
ESTILOS PROFESIONALES WES
================================= */
/* Variables CSS */
:root {
--wes-primary: #B19CD9;
--wes-secondary: #9B59B6;
--wes-success: #9DFF70;
--wes-warning: #FFE066;
--wes-danger: #FF6B6B;
--wes-info: #74B9FF;
--wes-light: #f6f7f7;
--wes-dark: #1d2327;
--wes-border: #c3c4c7;
--wes-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.wrap {
margin: 20px 20px 0 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
/* Header mejorado */
.wes-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding: 20px;
background: linear-gradient(135deg, var(--wes-primary), var(--wes-secondary));
border-radius: 12px;
color: white;
box-shadow: var(--wes-shadow);
}
.wes-header h1 {
margin: 0;
font-size: 28px;
font-weight: 600;
}
.wes-header p {
margin: 5px 0 0;
opacity: 0.9;
font-size: 16px;
}
.btn-new-student {
background: white;
color: var(--wes-primary);
border: none;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.btn-new-student:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
/* Estadísticas mejoradas */
.wes-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: white;
padding: 25px;
border-radius: 12px;
border: 1px solid var(--wes-border);
text-align: center;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: var(--stat-color, var(--wes-primary));
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: var(--wes-shadow);
}
.stat-card.total { --stat-color: var(--wes-primary); }
.stat-card.active { --stat-color: var(--wes-success); }
.stat-card.new { --stat-color: var(--wes-warning); }
.stat-number {
font-size: 3em;
font-weight: 700;
margin: 0;
color: var(--stat-color, var(--wes-primary));
}
.stat-label {
margin: 10px 0 0;
color: #666;
font-weight: 500;
font-size: 16px;
}
/* Búsqueda mejorada */
.wes-search {
background: white;
padding: 25px;
border-radius: 12px;
border: 1px solid var(--wes-border);
margin-bottom: 25px;
box-shadow: var(--wes-shadow);
}
.search-grid {
display: grid;
grid-template-columns: 1fr auto auto auto;
gap: 20px;
align-items: end;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: var(--wes-dark);
}
.form-control {
width: 100%;
padding: 12px 16px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 14px;
transition: all 0.3s ease;
}
.form-control:focus {
outline: none;
border-color: var(--wes-primary);
box-shadow: 0 0 0 3px rgba(0, 115, 170, 0.1);
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-primary {
background: var(--wes-primary);
color: white;
}
.btn-primary:hover {
background: var(--wes-secondary);
transform: translateY(-1px);
}
.btn-secondary {
background: #6c757d;
color: white;
}
/* Tabla profesional */
.wes-table-container {
background: white;
border-radius: 12px;
border: 1px solid var(--wes-border);
overflow: hidden;
box-shadow: var(--wes-shadow);
}
.table-header {
padding: 20px 25px;
background: var(--wes-light);
border-bottom: 1px solid var(--wes-border);
display: flex;
justify-content: space-between;
align-items: center;
}
.table-header h2 {
margin: 0;
font-size: 20px;
color: var(--wes-dark);
}
/* Tabla mejorada */
.wes-table {
width: 100%;
border-collapse: collapse;
margin: 0;
}
.wes-table thead {
background: #f8f9fa;
}
.wes-table th {
padding: 16px 20px;
text-align: left;
font-weight: 600;
color: var(--wes-dark);
border-bottom: 2px solid var(--wes-border);
font-size: 14px;
}
.wes-table td {
padding: 16px 20px;
border-bottom: 1px solid #f0f0f0;
vertical-align: middle;
}
.wes-table tbody tr {
transition: all 0.3s ease;
}
.wes-table tbody tr:hover {
background: #f8f9ff;
}
/* Estados mejorados */
.status-badge {
padding: 6px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.status-active {
background: #d4edda;
color: #155724;
}
.status-inactive {
background: #f8d7da;
color: #721c24;
}
.status-graduated {
background: #d1ecf1;
color: #0c5460;
}
.status-suspended {
background: #fff3cd;
color: #856404;
}
.status-retired {
background: #e2e3e5;
color: #383d41;
}
/* Botones de acción */
.action-buttons {
display: flex;
gap: 8px;
}
.btn-sm {
padding: 8px 12px;
font-size: 12px;
border-radius: 6px;
}
.btn-edit {
background: var(--wes-info);
color: white;
}
.btn-edit:hover {
background: #0087be;
}
.btn-delete {
background: var(--wes-danger);
color: white;
}
.btn-delete:hover {
background: #b02a2c;
}
.btn-status {
background: var(--wes-warning);
color: white;
}
.btn-status:hover {
background: #c69c00;
}
/* Modal mejorado */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
z-index: 999999;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.modal-overlay.show {
opacity: 1;
visibility: visible;
}
.modal-content {
background: white;
border-radius: 16px;
max-width: 900px;
width: 95%;
max-height: 95vh;
overflow: hidden;
transform: scale(0.9);
transition: all 0.3s ease;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
}
.modal-overlay.show .modal-content {
transform: scale(1);
}
.modal-header {
padding: 25px 70px 25px 30px;
background: linear-gradient(135deg, var(--wes-primary), var(--wes-secondary));
color: white;
position: relative;
flex-shrink: 0;
text-align: center;
}
.modal-title {
margin: 0;
font-size: 24px;
font-weight: 600;
}
.modal-subtitle {
margin: 8px 0 0;
opacity: 0.9;
font-size: 16px;
}
.btn-close {
position: absolute;
top: 15px;
right: 20px;
background: rgba(255,255,255,0.2);
border: none;
color: white;
font-size: 28px;
font-weight: bold;
cursor: pointer;
padding: 8px 12px;
border-radius: 6px;
transition: all 0.3s ease;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
.btn-close:hover {
background: rgba(255, 255, 255, 0.2);
}
/* Tabs mejorados */
.modal-tabs {
display: flex;
background: #f8f9fa;
border-bottom: 1px solid var(--wes-border);
flex-shrink: 0;
}
.tab-btn {
flex: 1;
padding: 16px 20px;
border: none;
background: none;
cursor: pointer;
font-weight: 500;
color: #666;
border-bottom: 3px solid transparent;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.tab-btn.active {
background: white;
color: var(--wes-primary);
border-bottom-color: var(--wes-primary);
}
.tab-btn:hover:not(.active) {
background: #f0f0f0;
color: var(--wes-dark);
}
/* Contenido del formulario */
.modal-body {
padding: 30px;
flex-grow: 1;
overflow-y: auto;
min-height: 0;
max-height: 60vh;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.tab-title {
margin: 0 0 25px;
font-size: 20px;
color: var(--wes-primary);
display: flex;
align-items: center;
gap: 10px;
}
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
.form-group-full {
grid-column: 1 / -1;
}
.form-group {
margin-bottom: 20px;
}
.help-text {
font-size: 12px;
color: #666;
margin-top: 5px;
}
.info-box {
background: #e7f3ff;
border: 1px solid #b8daff;
border-radius: 8px;
padding: 15px;
margin-top: 20px;
}
.info-box p {
margin: 0;
color: #004085;
font-size: 14px;
}
/* Footer del modal - MEJORADO PARA NO CORTARSE */
.modal-footer {
padding: 20px 30px;
background: #f8f9fa;
border-top: 1px solid var(--wes-border);
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
min-height: 70px;
flex-wrap: nowrap;
}
.btn-nav {
display: flex;
align-items: center;
gap: 8px;
}
.modal-footer > div {
display: flex;
gap: 10px;
align-items: center;
}
/* Dropdown para estados */
.status-dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: white;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
border-radius: 8px;
border: 1px solid var(--wes-border);
overflow: hidden;
bottom: 100%;
right: 0;
}
.dropdown-content.show {
display: block;
}
.dropdown-item {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
cursor: pointer;
transition: all 0.3s ease;
}
.dropdown-item:hover {
background-color: #f1f1f1;
}
/* Loading spinner */
.spinner {
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid #f3f3f3;
border-top: 2px solid var(--wes-primary);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Estados vacío mejorado */
.empty-state {
padding: 60px 20px;
text-align: center;
color: #646970;
}
.empty-icon {
font-size: 4em;
color: #dcdcde;
margin-bottom: 20px;
}
.empty-title {
font-size: 24px;
margin-bottom: 10px;
color: var(--wes-dark);
}
.empty-description {
font-size: 16px;
margin-bottom: 25px;
}
/* Responsive */
@media (max-width: 768px) {
.wes-header {
flex-direction: column;
gap: 15px;
text-align: center;
}
.search-grid {
grid-template-columns: 1fr;
gap: 15px;
}
.form-grid {
grid-template-columns: 1fr;
}
.modal-content {
width: 98%;
margin: 10px;
max-height: 95vh;
}
.tab-btn {
font-size: 12px;
padding: 12px 8px;
}
.tab-btn i {
display: none;
}
.action-buttons {
flex-direction: column;
}
}
</style>
<div class="wrap">
<!-- Header mejorado -->
<div class="wes-header">
<div>
<h1><i class="fas fa-users"></i> Gestión de Estudiantes</h1>
<p>Administra toda la información de tus estudiantes de forma profesional</p>
</div>
<button class="btn-new-student" onclick="openStudentModal()">
<i class="fas fa-plus"></i>
Nuevo Estudiante
</button>
</div>
<!-- Estadísticas mejoradas -->
<div class="wes-stats">
<div class="stat-card total">
<h2 class="stat-number"><?php echo $total_students; ?></h2>
<p class="stat-label">Total Estudiantes</p>
</div>
<div class="stat-card active">
<h2 class="stat-number"><?php echo count($active_students); ?></h2>
<p class="stat-label">Activos</p>
</div>
<div class="stat-card new">
<h2 class="stat-number"><?php echo count($new_students); ?></h2>
<p class="stat-label">Nuevos (30 días)</p>
</div>
</div>
<!-- Búsqueda mejorada -->
<div class="wes-search">
<div class="search-grid">
<div class="form-group">
<label>Buscar estudiante</label>
<input type="text" class="form-control" id="search-input" placeholder="Nombre, email, teléfono o ID...">
</div>
<div class="form-group">
<label>Estado</label>
<select class="form-control" id="status-filter">
<option value="">Todos</option>
<option value="active">Activos</option>
<option value="inactive">Inactivos</option>
<option value="graduated">Graduados</option>
<option value="suspended">Suspendidos</option>
<option value="retired">Retirados</option>
</select>
</div>
<div>
<button class="btn btn-primary" onclick="searchStudents()">
<i class="fas fa-search"></i> Buscar
</button>
</div>
<div>
<button class="btn btn-secondary" onclick="clearSearch()">
<i class="fas fa-times"></i> Limpiar
</button>
</div>
</div>
</div>
<!-- Tabla mejorada -->
<div class="wes-table-container">
<div class="table-header">
<h2>Lista de Estudiantes</h2>
</div>
<?php if (empty($students)): ?>
<!-- Estado vacío -->
<div class="empty-state">
<div class="empty-icon">
<i class="fas fa-users"></i>
</div>
<h3 class="empty-title">No hay estudiantes registrados</h3>
<p class="empty-description">Comienza agregando tu primer estudiante al sistema</p>
<button class="btn btn-primary" onclick="openStudentModal()">
<i class="fas fa-plus"></i>
Agregar Primer Estudiante
</button>
</div>
<?php else: ?>
<!-- Tabla de estudiantes -->
<table class="wes-table">
<thead>
<tr>
<th>ID</th>
<th>Nombre Completo</th>
<th>Email</th>
<th>Teléfono</th>
<th>País</th>
<th>Estado</th>
<th>Fecha Registro</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<?php foreach ($students as $student): ?>
<tr>
<td><strong><?php echo esc_html($student->student_id); ?></strong></td>
<td>
<div style="font-weight: 600;"><?php echo esc_html($student->first_name . ' ' . $student->last_name); ?></div>
</td>
<td><?php echo $student->email ? esc_html($student->email) : '<span style="color: #999;">Sin email</span>'; ?></td>
<td><?php echo esc_html($student->phone ?: '-'); ?></td>
<td><?php echo esc_html($student->country_of_origin ?: '-'); ?></td>
<td>
<span class="status-badge status-<?php echo $student->status; ?>">
<?php echo ucfirst($student->status); ?>
</span>
</td>
<td><?php echo date('d/m/Y', strtotime($student->created_at)); ?></td>
<td>
<div class="action-buttons">
<button class="btn btn-edit btn-sm" onclick="editStudent(<?php echo $student->id; ?>)" title="Editar">
<i class="fas fa-edit"></i>
</button>
<button class="btn btn-status btn-sm" onclick="showStatusDropdown(event, <?php echo $student->id; ?>)" title="Cambiar Estado">
<i class="fas fa-exchange-alt"></i>
</button>
<button class="btn btn-delete btn-sm" onclick="deleteStudent(<?php echo $student->id; ?>)" title="Eliminar">
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</div>
<!-- Modal completo para agregar/editar estudiante -->
<div class="modal-overlay" id="student-modal">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title" id="modal-title">Nuevo Estudiante</h2>
<p class="modal-subtitle" id="modal-subtitle">Completa la información del estudiante</p>
<button class="btn-close" onclick="closeStudentModal()">×</button>
</div>
<div class="modal-tabs">
<button class="tab-btn active" data-tab="personal">
<i class="fas fa-user"></i>
Datos Personales
</button>
<button class="tab-btn" data-tab="contact">
<i class="fas fa-phone"></i>
Contacto
</button>
<button class="tab-btn" data-tab="emergency">
<i class="fas fa-exclamation-triangle"></i>
Emergencia
</button>
<button class="tab-btn" data-tab="additional">
<i class="fas fa-info-circle"></i>
Adicional
</button>
</div>
<form id="student-form">
<div class="modal-body">
<!-- Tab 1: Datos Personales -->
<div class="tab-content active" id="personal-tab">
<h3 class="tab-title">
<i class="fas fa-user"></i>
Información Personal
</h3>
<div class="form-grid">
<div class="form-group">
<label>Nombre *</label>
<input type="text" name="first_name" id="first_name" class="form-control">
</div>
<div class="form-group">
<label>Apellido *</label>
<input type="text" name="last_name" id="last_name" class="form-control">
</div>
</div>
<div class="form-grid">
<div class="form-group">
<label>Fecha de Nacimiento</label>
<input type="date" name="date_of_birth" id="date_of_birth" class="form-control">
</div>
<div class="form-group">
<label>Género</label>
<select name="gender" id="gender" class="form-control">
<option value="">Seleccionar...</option>
<option value="male">Masculino</option>
<option value="female">Femenino</option>
<option value="other">Otro</option>
<option value="prefer_not_to_say">Prefiero no decir</option>
</select>
</div>
</div>
<div class="form-grid">
<div class="form-group">
<label>País de Origen</label>
<select name="country_of_origin" id="country_of_origin" class="form-control">
<option value="">Seleccionar país...</option>
<option value="Guatemala">Guatemala</option>
<option value="México">México</option>
<option value="Estados Unidos">Estados Unidos</option>
<option value="Honduras">Honduras</option>
<option value="El Salvador">El Salvador</option>
<option value="Nicaragua">Nicaragua</option>
<option value="Costa Rica">Costa Rica</option>
<option value="Panamá">Panamá</option>
<option value="Colombia">Colombia</option>
<option value="España">España</option>
<option value="Otro">Otro</option>
</select>
</div>
<div class="form-group">
<label>Nacionalidad</label>
<input type="text" name="nationality" id="nationality" class="form-control" placeholder="Ej: Guatemalteca">
</div>
</div>
<div class="form-group form-group-full">
<label>Documento de Identidad</label>
<input type="text" name="identity_document" id="identity_document" class="form-control" placeholder="DPI, Pasaporte, Cédula, etc.">
</div>
</div>
<!-- Tab 2: Información de Contacto -->
<div class="tab-content" id="contact-tab">
<h3 class="tab-title">
<i class="fas fa-phone"></i>
Información de Contacto
</h3>
<div class="form-group">
<label>Email Personal</label>
<input type="email" name="email" id="email" class="form-control" placeholder="estudiante@email.com">
<div class="help-text">Email principal de comunicación (opcional)</div>
</div>
<div class="form-group">
<label>Teléfono Personal</label>
<input type="tel" name="phone" id="phone" class="form-control" placeholder="Ej: +502 1234-5678">
</div>
<div class="form-grid">
<div class="form-group">
<label>Ciudad</label>
<input type="text" name="city" id="city" class="form-control" placeholder="Ciudad donde reside">
</div>
</div>
<div class="form-group">
<label>Dirección Completa</label>
<textarea name="address" id="address" rows="3" class="form-control" placeholder="Dirección completa del estudiante"></textarea>
</div>
</div>
<!-- Tab 3: Contacto de Emergencia -->
<div class="tab-content" id="emergency-tab">
<h3 class="tab-title">
<i class="fas fa-exclamation-triangle"></i>
Contacto de Emergencia
</h3>
<div class="form-group">
<label>Nombre del Responsable/Tutor</label>
<input type="text" name="emergency_contact" id="emergency_contact" class="form-control" placeholder="Nombre completo del contacto de emergencia">
</div>
<div class="form-grid">
<div class="form-group">
<label>Email del Responsable</label>
<input type="email" name="emergency_email" id="emergency_email" class="form-control" placeholder="responsable@email.com">
</div>
<div class="form-group">
<label>Teléfono de Emergencia</label>
<input type="tel" name="emergency_phone" id="emergency_phone" class="form-control" placeholder="Ej: +502 1234-5678">
</div>
</div>
<div class="form-group">
<label>Relación</label>
<select name="emergency_relationship" id="emergency_relationship" class="form-control">
<option value="">Seleccionar relación...</option>
<option value="parent">Padre/Madre</option>
<option value="guardian">Tutor/Guardián</option>
<option value="spouse">Cónyuge</option>
<option value="sibling">Hermano/a</option>
<option value="friend">Amigo/a</option>
<option value="other">Otro</option>
</select>
</div>
<div class="info-box">
<p>
<i class="fas fa-info-circle"></i>
<strong>Información importante:</strong> Esta información se usará únicamente en caso de emergencia y es completamente opcional.
</p>
</div>
</div>
<!-- Tab 4: Información Adicional -->
<div class="tab-content" id="additional-tab">
<h3 class="tab-title">
<i class="fas fa-info-circle"></i>
Información Adicional
</h3>
<div class="form-group">
<label>¿Cómo se enteró de la academia?</label>
<select name="how_did_you_hear" id="how_did_you_hear" class="form-control">
<option value="">Seleccionar opción...</option>
<option value="facebook">Facebook</option>
<option value="instagram">Instagram</option>
<option value="google">Google/Internet</option>
<option value="friend_family">Amigo/Familiar</option>
<option value="student">Estudiante actual</option>
<option value="flyer">Volante/Publicidad</option>
<option value="radio">Radio</option>
<option value="newspaper">Periódico</option>
<option value="street_sign">Rótulo en la calle</option>
<option value="other">Otro</option>
</select>
</div>
<div class="form-group">
<label>¿Quién lo refirió?</label>
<input type="text" name="referred_by" id="referred_by" class="form-control" placeholder="Nombre de la persona que lo refirió (opcional)">
</div>
<div class="form-group">
<label>Observaciones Especiales</label>
<textarea name="special_notes" id="special_notes" rows="4" class="form-control" placeholder="Cualquier información adicional relevante..."></textarea>
</div>
</div>
</div>
<div class="modal-footer">
<div>
<button type="button" class="btn btn-secondary btn-nav" id="prev-tab" style="display: none;" onclick="previousTab()">
<i class="fas fa-chevron-left"></i> Anterior
</button>
</div>
<div>
<button type="button" class="btn btn-secondary" onclick="closeStudentModal()">Cancelar</button>
<button type="button" class="btn btn-primary btn-nav" id="next-tab" onclick="nextTab()">
Siguiente <i class="fas fa-chevron-right"></i>
</button>
<button type="submit" class="btn btn-primary" id="save-btn" style="display: none;">
<i class="fas fa-save"></i> Guardar Estudiante
</button>
</div>
</div>
<input type="hidden" name="student_id" id="student_id" value="0">
</form>
</div>
</div>
<!-- Dropdown para cambio de estado -->
<div class="status-dropdown" id="status-dropdown" style="display: none;">
<div class="dropdown-content" id="status-dropdown-content">
<a class="dropdown-item" onclick="changeStudentStatus('active')">
<i class="fas fa-check-circle" style="color: var(--wes-success);"></i> Activo
</a>
<a class="dropdown-item" onclick="changeStudentStatus('inactive')">
<i class="fas fa-times-circle" style="color: var(--wes-danger);"></i> Inactivo
</a>
<a class="dropdown-item" onclick="changeStudentStatus('graduated')">
<i class="fas fa-graduation-cap" style="color: var(--wes-info);"></i> Graduado
</a>
<a class="dropdown-item" onclick="changeStudentStatus('suspended')">
<i class="fas fa-pause-circle" style="color: var(--wes-warning);"></i> Suspendido
</a>
<a class="dropdown-item" onclick="changeStudentStatus('retired')">
<i class="fas fa-sign-out-alt" style="color: #6c757d;"></i> Retirado
</a>
</div>
</div>
<script>
jQuery(document).ready(function($) {
// Variables globales
let currentTab = 0;
let currentStudentId = null;
const tabs = ['personal', 'contact', 'emergency', 'additional'];
// Event listeners
initializeEventListeners();
function initializeEventListeners() {
// Tabs
$('.tab-btn').click(function() {
const targetTab = $(this).data('tab');
const tabIndex = tabs.indexOf(targetTab);
showTab(tabIndex);
});
// Form submission - PREVENIR validación HTML5
$('#student-form').submit(function(e) {
e.preventDefault();
e.stopPropagation();
saveStudent();
return false;
});
// Search functionality
$('#search-input').keyup(function(e) {
if (e.key === 'Enter') {
searchStudents();
}
});
// Close modal on outside click
$('#student-modal').click(function(e) {
if (e.target === this) {
closeStudentModal();
}
});
}
// Modal management
window.openStudentModal = function(studentId = null, mode = 'create') {
currentStudentId = studentId;
const modal = $('#student-modal');
const title = $('#modal-title');
const subtitle = $('#modal-subtitle');
// Resetear formulario PRIMERO
resetForm();
if (mode === 'edit' && studentId) {
title.text('Editar Estudiante');
subtitle.text('Actualiza la información del estudiante');
// Mostrar modal
modal.addClass('show');
showTab(0);
// Cargar datos después de mostrar
setTimeout(() => {
loadStudentData(studentId);
}, 500);
} else {
title.text('Nuevo Estudiante');
subtitle.text('Completa la información del estudiante');
modal.addClass('show');
showTab(0);
}
};
window.closeStudentModal = function() {
const modal = $('#student-modal');
modal.removeClass('show');
setTimeout(() => {
resetForm();
}, 300);
};
function loadStudentData(studentId) {
console.log('Cargando datos para estudiante ID:', studentId);
$.post('<?php echo admin_url('admin-ajax.php'); ?>', {
action: 'wes_get_student',
nonce: '<?php echo wp_create_nonce('wes_nonce'); ?>',
student_id: studentId
})
.done(function(response) {
console.log('Respuesta del servidor:', response);
if (response.success) {
const student = response.data;
// Llenar campos inmediatamente
Object.keys(student).forEach(key => {
const field = document.getElementById(key);
if (field && student[key] !== null && student[key] !== undefined) {
field.value = student[key];
console.log(`Campo ${key} llenado con: ${student[key]}`);
}
});
$('#student_id').val(studentId);
showNotification('Datos cargados correctamente', 'success');
} else {
console.error('Error del servidor:', response.data);
showNotification('Error al cargar los datos: ' + response.data, 'error');
}
})
.fail(function(xhr, status, error) {
console.error('Error AJAX:', error, xhr.responseText);
showNotification('Error de conexión al cargar los datos', 'error');
});
}
function resetForm() {
// Limpiar todos los campos
$('#student-form')[0].reset();
$('#student_id').val('0');
currentStudentId = null;
currentTab = 0;
// Remover atributos required problemáticos
$('#student-form input[required], #student-form select[required], #student-form textarea[required]').each(function() {
$(this).removeAttr('required');
});
}
// Tab navigation
function showTab(tabIndex) {
currentTab = tabIndex;
// Hide all tabs
$('.tab-content').removeClass('active');
$('.tab-btn').removeClass('active');
// Show current tab
$(`#${tabs[tabIndex]}-tab`).addClass('active');
$(`.tab-btn[data-tab="${tabs[tabIndex]}"]`).addClass('active');
// Update navigation buttons
$('#prev-tab').toggle(tabIndex > 0);
$('#next-tab').toggle(tabIndex < tabs.length - 1);
$('#save-btn').toggle(tabIndex === tabs.length - 1);
}
window.nextTab = function() {
if (validateCurrentTab() && currentTab < tabs.length - 1) {
showTab(currentTab + 1);
}
};
window.previousTab = function() {
if (currentTab > 0) {
showTab(currentTab - 1);
}
};
function validateCurrentTab() {
const currentTabName = tabs[currentTab];
if (currentTabName === 'personal') {
const firstName = $('#first_name').val().trim();
const lastName = $('#last_name').val().trim();
if (!firstName) {
showNotification('El nombre es requerido', 'error');
$('#first_name').focus();
return false;
}
if (!lastName) {
showNotification('El apellido es requerido', 'error');
$('#last_name').focus();
return false;
}
}
if (currentTabName === 'contact') {
const email = $('#email').val().trim();
if (email && !isValidEmail(email)) {
showNotification('El formato del email no es válido', 'error');
$('#email').focus();
return false;
}
}
return true;
}
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
// Student operations
window.editStudent = function(studentId) {
console.log('Editando estudiante:', studentId);
openStudentModal(studentId, 'edit');
};
window.deleteStudent = function(studentId) {
if (!confirm('¿Estás seguro de eliminar este estudiante?\n\nEsta acción no se puede deshacer.')) {
return;
}
$.post('<?php echo admin_url('admin-ajax.php'); ?>', {
action: 'wes_delete_student',
nonce: '<?php echo wp_create_nonce('wes_nonce'); ?>',
student_id: studentId
})
.done(function(response) {
if (response.success) {
showNotification('Estudiante eliminado correctamente', 'success');
setTimeout(() => {
location.reload();
}, 1000);
} else {
showNotification('Error al eliminar: ' + response.data, 'error');
}
})
.fail(function() {
showNotification('Error de conexión al eliminar', 'error');
});
};
window.showStatusDropdown = function(event, studentId) {
event.stopPropagation();
currentStudentId = studentId;
const dropdown = $('#status-dropdown');
const dropdownContent = $('#status-dropdown-content');
// Position the dropdown
const rect = event.target.getBoundingClientRect();
dropdown.css({
position: 'fixed',
top: rect.bottom + 5 + 'px',
left: rect.left + 'px',
display: 'block'
});
dropdownContent.addClass('show');
// Close dropdown when clicking outside
setTimeout(() => {
$(document).on('click', closeStatusDropdown);
}, 100);
};
function closeStatusDropdown() {
const dropdown = $('#status-dropdown');
const dropdownContent = $('#status-dropdown-content');
dropdownContent.removeClass('show');
dropdown.hide();
$(document).off('click', closeStatusDropdown);
}
// FUNCIÓN ARREGLADA CON VALIDACIÓN DE ESTADO ACTUAL
window.changeStudentStatus = function(newStatus) {
if (!currentStudentId) return;
// Obtener estado actual del estudiante desde la tabla
const currentRow = document.querySelector(`button[onclick="editStudent(${currentStudentId})"]`).closest('tr');
const currentStatusElement = currentRow.querySelector('.status-badge');
const currentStatus = currentStatusElement.className.includes('status-active') ? 'active' :
currentStatusElement.className.includes('status-inactive') ? 'inactive' :
currentStatusElement.className.includes('status-graduated') ? 'graduated' :
currentStatusElement.className.includes('status-suspended') ? 'suspended' : 'retired';
// Si es el mismo estado, no hacer nada
if (currentStatus === newStatus) {
showNotification('El estudiante ya tiene ese estado', 'info');
closeStatusDropdown();
return;
}
const statusLabels = {
'active': 'Activo',
'inactive': 'Inactivo',
'graduated': 'Graduado',
'suspended': 'Suspendido',
'retired': 'Retirado'
};
if (!confirm(`¿Cambiar estado del estudiante a "${statusLabels[newStatus]}"?`)) {
closeStatusDropdown();
return;
}
$.post('<?php echo admin_url('admin-ajax.php'); ?>', {
action: 'wes_update_student_status',
nonce: '<?php echo wp_create_nonce('wes_nonce'); ?>',
student_id: currentStudentId,
status: newStatus
})
.done(function(response) {
if (response.success) {
showNotification(`Estado cambiado a "${statusLabels[newStatus]}"`, 'success');
setTimeout(() => {
location.reload();
}, 1000);
} else {
showNotification('Error al cambiar estado: ' + response.data, 'error');
}
})
.fail(function() {
showNotification('Error de conexión al cambiar estado', 'error');
});
closeStatusDropdown();
};
function saveStudent() {
console.log('Iniciando guardado...');
// Validar manualmente SIN usar validación HTML5
if (!validateCurrentTab()) {
return;
}
const saveBtn = $('#save-btn');
const originalText = saveBtn.html();
// Show loading
saveBtn.html('<div class="spinner"></div> Guardando...').prop('disabled', true);
// Preparar datos del formulario
const formData = {
action: 'wes_save_student',
nonce: '<?php echo wp_create_nonce('wes_nonce'); ?>',
student_id: $('#student_id').val(),
// Datos Personales
first_name: $('#first_name').val().trim(),
last_name: $('#last_name').val().trim(),
date_of_birth: $('#date_of_birth').val(),
gender: $('#gender').val(),
country_of_origin: $('#country_of_origin').val(),
nationality: $('#nationality').val(),
identity_document: $('#identity_document').val(),
// Información de Contacto
email: $('#email').val().trim(),
phone: $('#phone').val(),
city: $('#city').val(),
address: $('#address').val(),
// Responsables/Contacto de Emergencia
emergency_contact: $('#emergency_contact').val(),
emergency_email: $('#emergency_email').val(),
emergency_phone: $('#emergency_phone').val(),
emergency_relationship: $('#emergency_relationship').val(),
// Información Adicional
how_did_you_hear: $('#how_did_you_hear').val(),
referred_by: $('#referred_by').val(),
special_notes: $('#special_notes').val(),
// Campos del sistema
current_level: 'beginner',
status: 'active',
notes: $('#special_notes').val()
};
console.log('Datos a enviar:', formData);
$.post('<?php echo admin_url('admin-ajax.php'); ?>', formData)
.done(function(response) {
console.log('Respuesta del servidor:', response);
if (response.success) {
const isEdit = parseInt($('#student_id').val()) > 0;
const message = isEdit ? 'Estudiante actualizado correctamente' : 'Estudiante registrado correctamente';
showNotification(message, 'success');
closeStudentModal();
setTimeout(() => {
location.reload();
}, 1000);
} else {
showNotification('Error: ' + response.data, 'error');
}
})
.fail(function(xhr, status, error) {
console.error('Error AJAX:', error, xhr.responseText);
showNotification('Error de conexión. Intenta de nuevo.', 'error');
})
.always(function() {
saveBtn.html(originalText).prop('disabled', false);
});
}
// Search functions
window.searchStudents = function() {
const searchTerm = $('#search-input').val();
const statusFilter = $('#status-filter').val();
const params = new URLSearchParams();
if (searchTerm) params.append('search', searchTerm);
if (statusFilter) params.append('status', statusFilter);
if (params.toString()) {
const currentParams = new URLSearchParams(window.location.search);
const pageParam = currentParams.get('page');
if (pageParam) {
params.set('page', pageParam);
}
window.location.href = window.location.pathname + '?' + params.toString();
}
};
window.clearSearch = function() {
$('#search-input').val('');
$('#status-filter').val('');
window.location.href = window.location.pathname;
};
// Utility functions
function showNotification(message, type) {
// Crear notificación estilo WordPress
const alertClass = type === 'success' ? 'updated' : (type === 'info' ? 'update-nag' : 'error');
const notification = $(`
<div class="notice notice-${type} is-dismissible" style="margin: 20px 0;">
<p><strong>${message}</strong></p>
<button type="button" class="notice-dismiss">
<span class="screen-reader-text">Descartar este aviso.</span>
</button>
</div>
`);
$('.wrap').prepend(notification);
setTimeout(function() {
notification.fadeOut(function() {
$(this).remove();
});
}, 5000);
notification.find('.notice-dismiss').click(function() {
notification.fadeOut(function() {
$(this).remove();
});
});
}
// Inicializar
showTab(0);
});
</script>