academy/views/revisa.php

1360 lines
46 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
require_once __DIR__ . '/../config/app.php';
if (!is_logged_in()) {
header('Location: ' . asset('views/login.php'));
exit;
}
$page_title = 'VD_ - Revisión de datos';
require_once __DIR__ . '/../partials/header.php';
?>
<link rel="stylesheet" href="../css/views/revisa.css">
<!-- Modal Editar Participante -->
<div class="modal fade" id="modalEditarParticipante" tabindex="-1" aria-labelledby="modalEditarParticipanteLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content rounded-3 shadow">
<div class="modal-header bg-light">
<h5 class="modal-title text-primary fw-semibold" id="modalEditarParticipanteLabel">
<i class="bi bi-pencil-square me-2"></i>
<span id="modalTituloEditar">Editar Participante</span>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
</div>
<div class="modal-body">
<form id="formEditarParticipante" class="needs-validation" novalidate>
<input type="hidden" id="edit_id" name="id">
<div class="accordion" id="accordionCursosEditar">
<!-- Bridging Program -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingBPEdit">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBPEdit" aria-expanded="true" aria-controls="collapseBPEdit">
Bridging Program
</button>
</h2>
<div id="collapseBPEdit" class="accordion-collapse collapse show" aria-labelledby="headingBPEdit" data-bs-parent="#accordionCursosEditar">
<div class="accordion-body">
<div class="row g-4">
<div class="col-12">
<div class="fw-semibold mb-1">Bridging Program: selecciona fecha y lugar</div>
</div>
<div class="col-12 col-lg-6">
<label for="edit_fecha_bp" class="form-label">Fecha</label>
<select class="form-select validar-edit" id="edit_fecha_bp" name="fecha_bp" required>
<option value="">Seleccione una opción…</option>
</select>
</div>
<div class="col-12 col-lg-6">
<label for="edit_lugar_bp" class="form-label">Lugar</label>
<select class="form-select validar-edit" id="edit_lugar_bp" name="lugar_bp" required>
<option value="">Seleccione un lugar…</option>
<option value="V">Capacitación Villagra</option>
<option value="A">Aguas Blancas</option>
</select>
</div>
</div>
</div>
</div>
</div>
<!-- Bloque 1 -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingB1Edit">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseB1Edit" aria-expanded="false" aria-controls="collapseB1Edit">
Bloque 1
</button>
</h2>
<div id="collapseB1Edit" class="accordion-collapse collapse" aria-labelledby="headingB1Edit" data-bs-parent="#accordionCursosEditar">
<div class="accordion-body">
<div class="row g-4">
<div class="col-12 col-xl-6">
<div class="row g-4">
<div class="col-12">
<div class="fw-semibold mb-1">Día 1: selecciona fecha y lugar</div>
</div>
<div class="col-12 col-md-6">
<label for="edit_fecha_b1_1" class="form-label">Fecha</label>
<select class="form-select validar-edit" id="edit_fecha_b1_1" name="fecha_b1_1" required>
<option value="">Seleccione una opción…</option>
</select>
</div>
<div class="col-12 col-md-6">
<label for="edit_lugar_b1_1" class="form-label">Lugar</label>
<select class="form-select validar-edit" id="edit_lugar_b1_1" name="lugar_b1_1" required>
<option value="">Seleccione un lugar…</option>
<option value="V">Capacitación Villagra</option>
<option value="A">Aguas Blancas</option>
</select>
</div>
</div>
</div>
<div class="col-12 col-xl-6">
<div class="row g-4">
<div class="col-12">
<div class="fw-semibold mb-1">Día 2: selecciona fecha y lugar</div>
</div>
<div class="col-12 col-md-6">
<label for="edit_fecha_b1_2" class="form-label">Fecha</label>
<select class="form-select validar-edit" id="edit_fecha_b1_2" name="fecha_b1_2" required>
<option value="">Seleccione una opción…</option>
</select>
</div>
<div class="col-12 col-md-6">
<label for="edit_lugar_b1_2" class="form-label">Lugar</label>
<select class="form-select validar-edit" id="edit_lugar_b1_2" name="lugar_b1_2" required>
<option value="">Seleccione un lugar…</option>
<option value="V">Capacitación Villagra</option>
<option value="A">Aguas Blancas</option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Bloque 2 -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingB2Edit">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseB2Edit" aria-expanded="false" aria-controls="collapseB2Edit">
Bloque 2
</button>
</h2>
<div id="collapseB2Edit" class="accordion-collapse collapse" aria-labelledby="headingB2Edit" data-bs-parent="#accordionCursosEditar">
<div class="accordion-body">
<div class="row g-4">
<div class="col-12 col-xl-6">
<div class="row g-4">
<div class="col-12">
<div class="fw-semibold mb-1">Día 1: selecciona fecha y lugar</div>
</div>
<div class="col-12 col-md-6">
<label for="edit_fecha_b2_1" class="form-label">Fecha</label>
<select class="form-select validar-edit" id="edit_fecha_b2_1" name="fecha_b2_1" required>
<option value="">Seleccione una opción…</option>
</select>
</div>
<div class="col-12 col-md-6">
<label for="edit_lugar_b2_1" class="form-label">Lugar</label>
<select class="form-select validar-edit" id="edit_lugar_b2_1" name="lugar_b2_1" required>
<option value="">Seleccione un lugar…</option>
<option value="V">Capacitación Villagra</option>
<option value="A">Aguas Blancas</option>
</select>
</div>
</div>
</div>
<div class="col-12 col-xl-6">
<div class="row g-4">
<div class="col-12">
<div class="fw-semibold mb-1">Día 2: selecciona fecha y lugar</div>
</div>
<div class="col-12 col-md-6">
<label for="edit_fecha_b2_2" class="form-label">Fecha</label>
<select class="form-select validar-edit" id="edit_fecha_b2_2" name="fecha_b2_2" required>
<option value="">Seleccione una opción…</option>
</select>
</div>
<div class="col-12 col-md-6">
<label for="edit_lugar_b2_2" class="form-label">Lugar</label>
<select class="form-select validar-edit" id="edit_lugar_b2_2" name="lugar_b2_2" required>
<option value="">Seleccione un lugar…</option>
<option value="V">Capacitación Villagra</option>
<option value="A">Aguas Blancas</option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Bloque 3 -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingB3Edit">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseB3Edit" aria-expanded="false" aria-controls="collapseB3Edit">
Bloque 3
</button>
</h2>
<div id="collapseB3Edit" class="accordion-collapse collapse" aria-labelledby="headingB3Edit" data-bs-parent="#accordionCursosEditar">
<div class="accordion-body">
<div class="row g-4">
<div class="col-12 col-xl-6">
<div class="row g-4">
<div class="col-12">
<div class="fw-semibold mb-1">Día 1: selecciona fecha y lugar</div>
</div>
<div class="col-12 col-md-6">
<label for="edit_fecha_b3_1" class="form-label">Fecha</label>
<select class="form-select validar-edit" id="edit_fecha_b3_1" name="fecha_b3_1">
<option value="">Seleccione una opción…</option>
</select>
</div>
<div class="col-12 col-md-6">
<label for="edit_lugar_b3_1" class="form-label">Lugar</label>
<select class="form-select validar-edit" id="edit_lugar_b3_1" name="lugar_b3_1">
<option value="">Seleccione un lugar…</option>
<option value="V">Capacitación Villagra</option>
<option value="A">Aguas Blancas</option>
</select>
</div>
</div>
</div>
<div class="col-12 col-xl-6">
<div class="row g-4">
<div class="col-12">
<div class="fw-semibold mb-1">Día 2: selecciona fecha y lugar</div>
</div>
<div class="col-12 col-md-6">
<label for="edit_fecha_b3_2" class="form-label">Fecha</label>
<select class="form-select validar-edit" id="edit_fecha_b3_2" name="fecha_b3_2">
<option value="">Seleccione una opción…</option>
</select>
</div>
<div class="col-12 col-md-6">
<label for="edit_lugar_b3_2" class="form-label">Lugar</label>
<select class="form-select validar-edit" id="edit_lugar_b3_2" name="lugar_b3_2">
<option value="">Seleccione un lugar…</option>
<option value="V">Capacitación Villagra</option>
<option value="A">Aguas Blancas</option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
<button type="button" class="btn btn-primary" id="btnGuardarEdicion">Guardar cambios</button>
</div>
</div>
</div>
</div>
<div class="container mt-4">
<div>Hola</div>
<div class="row"> <!-- Grilla -->
<div class="col-12">
<div id="pantallaGrilla" class="card shadow-sm rounded-3 overflow-hidden"
data-aos="fade-up"
data-aos-duration="600"
data-aos-easing="ease-out-cubic"
data-aos-delay="60"
data-aos-once="false">
<div class="card-header bg-light text-body border-bottom">
<h5 class="text-primary fw-semibold mb-0 p-md-2">
<i class="bi bi-people me-2"></i> Participantes
</h5>
</div>
<div class="card-body p-3 p-md-3">
<div id="lstTabla"></div>
</div>
</div>
</div>
</div> <!-- Grilla -->
<div class="row"> <!-- Formulario -->
<div class="col-12">
<div id="pantallaFormulario" class="card shadow-sm rounded-3 overflow-hidden d-none"
data-aos="fade-right"
data-aos-duration="650"
data-aos-easing="ease-out-cubic"
data-aos-delay="80"
data-aos-once="false">
<div class="card-header bg-light text-body border-bottom">
<h5 class="text-primary fw-semibold mb-0">
<i class="bi bi-person-fill-add me-2"></i> Nuevo Participante
</h5>
</div>
<div class="card-body">
<form id="miFormulario" class="row needs-validation" novalidate>
<!-- columna izquierda -->
<div class="col-md-6">
<div class="form-group mb-2">
<label class="col-form-label" for="nombre">
<span class="small">Nombre</span><span class="text-danger">*</span>
</label>
<input type="text" class="form-control form-control-sm" id="nombre" name="nombre"
placeholder="Ingrese el nombre" autocomplete="off" required>
<div class="invalid-feedback">Debe ingresar el nombre!</div>
</div>
<div class="form-group mb-2">
<label class="col-form-label" for="dni">
<span class="small">DNI</span><span class="text-danger">*</span>
</label>
<input type="text" class="form-control form-control-sm" id="dni" name="dni"
placeholder="Ingrese el documento" autocomplete="off" required>
<div class="invalid-feedback">Debe ingresar el dni!</div>
</div>
<div class="form-group mb-2">
<label class="col-form-label" for="departamento">
<span class="small">Departamento</span><span class="text-danger">*</span>
</label>
<select class="form-select form-select-sm" id="departamento" name="departamento" required>
<option value="" selected disabled>Seleccione el departamento</option>
<option value="Environment">Environment</option>
<option value="Finance">Finance</option>
<option value="Health and Safety">Health and Safety</option>
<option value="Legal">Legal</option>
<option value="Projects">Projects</option>
<option value="Security">Security</option>
<option value="Sustainable Development">Sustainable Development</option>
<option value="Exploration">Exploration</option>
<option value="General Services">General Services</option>
<option value="Human Resources">Human Resources</option>
<option value="IOC">IOC</option>
<option value="IT">IT</option>
<option value="LAMA">LAMA</option>
<option value="Lama Finance">Lama Finance</option>
<option value="Lama Supply Chain">Lama Supply Chain</option>
<option value="Mine Maintenance">Mine Maintenance</option>
<option value="Mine Operations">Mine Operations</option>
<option value="Mineral Resources">Mineral Resources</option>
<option value="Process">Process</option>
<option value="Supply Chain">Supply Chain</option>
<option value="Technical services ">Technical services </option>
</select>
<div class="invalid-feedback">Seleccione el departamento</div>
</div>
</div>
<!-- columna derecha -->
<div class="col-md-6">
<div class="form-group mb-2">
<label class="col-form-label" for="usuario">
<span class="small">Usuario</span><span class="text-danger">*</span>
</label>
<input type="text" class="form-control form-control-sm" id="usuario" name="usuario"
placeholder="Ingrese el usuario" autocomplete="off" required>
<div class="invalid-feedback">Debe ingresar el usuario!</div>
</div>
<div class="form-group mb-2">
<label class="col-form-label" for="email">
<span class="small">Email</span><span class="text-danger">*</span>
</label>
<input type="email" class="form-control form-control-sm" id="email" name="email"
placeholder="Ingrese el correo" autocomplete="off" required>
<div class="invalid-feedback">Debe ingresar el correo!</div>
</div>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-success me-2" id="btnGuardar">
<i class="bi bi-save2-fill me-1"></i> Guardar
</button>
<button type="button" class="btn btn-secondary" id="btnCancelar">
<i class="bi bi-arrow-left-short me-1"></i> Cancelar
</button>
</div>
</form>
</div>
</div>
</div>
</div> <!-- Formulario -->
</div>
<?php
require_once __DIR__ . '/../partials/footer.php';
?>
<script src="../js/cargar_datos.js"></script>
<script src="../js/convertir_form.js"></script>
<script>
const asistenciaText = (field, data) => {
const v = data[field];
if (v === null || typeof v === 'undefined') return 'n/a';
return (v == 1 || v === true) ? 'Si' : 'No';
};
function normAsistencia(v) {
if (v === '' || v === null || typeof v === 'undefined') return null;
const s = String(v).trim().toLowerCase();
if (v === true || s === 'true' || s === '1' || s === 'si' || s === 'sí') return 1;
if (v === false || s === 'false' || s === '0' || s === 'no') return 0;
return null;
}
function cargarFechasEdit(campoEdit) {
const campoBackend = campoEdit.replace(/^edit_fecha_/, "");
console.log("Cargando fechas para:", campoEdit, "=>", campoBackend);
return $.ajax({
url: "../ajax/fechas.ajax.php",
type: "POST",
dataType: "json",
data: {
campo: campoBackend
}
})
.done(function(respuesta) {
console.log("OK", campoEdit, respuesta);
const $sel = $("#" + campoEdit);
$sel.empty();
$sel.append(new Option("Seleccione una opción…", ""));
(respuesta || []).forEach(function(item) {
$sel.append(new Option(item.fecha, item.fecha));
});
})
.fail(function(xhr, status, error) {
console.error("Fallo en", campoEdit, {
status: status,
error: error,
responseText: xhr.responseText
});
});
}
function cargarCombosModalEdicion() {
const p1 = cargarFechasEdit("edit_fecha_bp");
const p2 = cargarFechasEdit("edit_fecha_b1_1");
const p3 = cargarFechasEdit("edit_fecha_b1_2");
const p4 = cargarFechasEdit("edit_fecha_b2_1");
const p5 = cargarFechasEdit("edit_fecha_b2_2");
const p6 = cargarFechasEdit("edit_fecha_b3_1");
const p7 = cargarFechasEdit("edit_fecha_b3_2");
return $.when(p1, p2, p3, p4, p5, p6, p7);
}
function normalizarLugar(valor) {
if (valor === null || typeof valor === 'undefined') return '';
const v = String(valor).trim().toUpperCase();
if (v === 'V' || v === 'VILLAGRA' || v === 'CAPACITACIÓN VILLAGRA' || v === 'CAPACITACION VILLAGRA') {
return 'V';
}
if (v === 'A' || v === 'AGUAS BLANCAS') {
return 'A';
}
return '';
}
function cargarDatosModalEdicion(rowData) {
$("#edit_id").val(rowData.id ?? "");
$("#modalTituloEditar").text(`Editar Participante: ${rowData.nombre ?? ""}`);
$("#edit_fecha_bp").val(rowData.fecha_bp ?? "").trigger("change");
$("#edit_lugar_bp").val(normalizarLugar(rowData.lugar_bp)).trigger("change");
$("#edit_fecha_b1_1").val(rowData.fecha_b1_1 ?? "").trigger("change");
$("#edit_lugar_b1_1").val(normalizarLugar(rowData.lugar_b1_1)).trigger("change");
$("#edit_fecha_b1_2").val(rowData.fecha_b1_2 ?? "").trigger("change");
$("#edit_lugar_b1_2").val(normalizarLugar(rowData.lugar_b1_2)).trigger("change");
$("#edit_fecha_b2_1").val(rowData.fecha_b2_1 ?? "").trigger("change");
$("#edit_lugar_b2_1").val(normalizarLugar(rowData.lugar_b2_1)).trigger("change");
$("#edit_fecha_b2_2").val(rowData.fecha_b2_2 ?? "").trigger("change");
$("#edit_lugar_b2_2").val(normalizarLugar(rowData.lugar_b2_2)).trigger("change");
$("#edit_fecha_b3_1").val(rowData.fecha_b3_1 ?? "").trigger("change");
$("#edit_lugar_b3_1").val(normalizarLugar(rowData.lugar_b3_1)).trigger("change");
$("#edit_fecha_b3_2").val(rowData.fecha_b3_2 ?? "").trigger("change");
$("#edit_lugar_b3_2").val(normalizarLugar(rowData.lugar_b3_2)).trigger("change");
}
function getPayloadEdicionParticipante() {
return {
accion: "EDITAR",
id: $("#edit_id").val(),
fecha_bp: $("#edit_fecha_bp").val(),
lugar_bp: $("#edit_lugar_bp").val(),
fecha_b1_1: $("#edit_fecha_b1_1").val(),
lugar_b1_1: $("#edit_lugar_b1_1").val(),
fecha_b1_2: $("#edit_fecha_b1_2").val(),
lugar_b1_2: $("#edit_lugar_b1_2").val(),
fecha_b2_1: $("#edit_fecha_b2_1").val(),
lugar_b2_1: $("#edit_lugar_b2_1").val(),
fecha_b2_2: $("#edit_fecha_b2_2").val(),
lugar_b2_2: $("#edit_lugar_b2_2").val(),
fecha_b3_1: $("#edit_fecha_b3_1").val(),
lugar_b3_1: $("#edit_lugar_b3_1").val(),
fecha_b3_2: $("#edit_fecha_b3_2").val(),
lugar_b3_2: $("#edit_lugar_b3_2").val()
};
}
function guardarEdicionParticipante() {
const payload = getPayloadEdicionParticipante();
return $.ajax({
url: "../ajax/usuarios.ajax.php",
type: "POST",
dataType: "json",
data: payload
});
}
$("#btnGuardarEdicion").on("click", function() {
const $btn = $(this);
const form = document.getElementById("formEditarParticipante");
if (!form.checkValidity()) {
form.classList.add("was-validated");
Swal.fire({
icon: "warning",
title: "Faltan datos",
text: "Completá todas las fechas y lugares requeridos."
});
return;
}
form.classList.add("was-validated");
$btn.prop("disabled", true);
guardarEdicionParticipante()
.done(function(resp) {
if (resp && resp.respuesta === "OK") {
bootstrap.Modal.getOrCreateInstance(
document.getElementById('modalEditarParticipante')
).hide();
Swal.fire({
toast: true,
position: "top",
icon: "success",
title: "Datos actualizados correctamente",
showConfirmButton: false,
timer: 2200,
timerProgressBar: true
});
const estadoGrid = grid.getPersistData();
$.ajax({
url: "../ajax/usuarios.ajax.php",
method: "POST",
data: {
accion: "LISTAR-DATOS-CURSO"
},
dataType: "json",
success: function(data) {
grid.dataSource = data;
const estado = JSON.parse(estadoGrid);
if (estado.filterSettings) grid.filterSettings = estado.filterSettings;
if (estado.searchSettings) grid.searchSettings = estado.searchSettings;
if (estado.sortSettings) grid.sortSettings = estado.sortSettings;
if (estado.pageSettings) grid.pageSettings = estado.pageSettings;
}
});
} else {
Swal.fire({
icon: "error",
title: "Error al actualizar",
text: resp?.mensaje || "No se pudieron guardar los cambios."
});
}
})
.fail(function(xhr) {
Swal.fire({
icon: "error",
title: "Error de comunicación",
text: xhr.responseText || "No se pudo contactar al servidor."
});
})
.always(function() {
$btn.prop("disabled", false);
});
});
let grid;
$.ajax({
url: '../ajax/usuarios.ajax.php',
method: 'POST',
data: {
accion: 'LISTAR-DATOS-CURSO'
},
dataType: 'json',
success: function(data) {
ej.grids.Grid.Inject(
ej.grids.Sort,
ej.grids.Search,
ej.grids.ColumnChooser,
ej.grids.Filter,
ej.grids.ExcelExport,
ej.grids.Page
);
grid = new ej.grids.Grid({
dataSource: data,
locale: 'es-ES',
clipMode: 'EllipsisWithTooltip',
allowTextWrap: false,
allowPaging: true,
allowSorting: true,
allowFiltering: true,
allowExcelExport: true,
showColumnChooser: true,
pageSettings: {
pageSize: 10
},
editSettings: {
allowEditing: true,
mode: 'Normal'
},
actionComplete: function(args) {
if (args.requestType !== 'save') return;
const curr = args.data ?? {};
const prev = args.previousData ?? {};
const id = curr.id;
if (!id) return;
// 1⃣ Detectar TODAS las asistencias modificadas
const cambios = {};
Object.keys(curr).forEach(k => {
if (!k.startsWith('asistencia_')) return;
const v1 = String(curr[k] ?? '');
const v2 = String(prev[k] ?? '');
if (v1 !== v2) {
cambios[k] = normAsistencia(curr[k]);
}
});
// Nada cambió → salir
if (Object.keys(cambios).length === 0) return;
// 2⃣ Armar POST
const fd = new FormData();
fd.append('accion', 'EDITAR');
fd.append('id', id);
Object.entries(cambios).forEach(([campo, valor]) => {
fd.append(campo, valor === null ? '' : String(valor));
});
// 3⃣ AJAX guardar
$.ajax({
url: "../ajax/usuarios.ajax.php",
method: "POST",
data: fd,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function(r) {
if (r?.respuesta === "OK") {
Swal.fire({
toast: true,
position: 'top',
icon: 'success',
title: 'Asistencia actualizada',
showConfirmButton: false,
timer: 1200
});
} else {
Swal.fire({
icon: 'error',
title: 'No se pudo guardar',
text: r?.mensaje || 'Error'
});
// 🔁 revertir TODOS los campos modificados
Object.keys(cambios).forEach(campo => {
grid.updateCell(args.rowIndex, campo, prev[campo]);
});
}
},
error: function(xhr) {
Swal.fire({
icon: 'error',
title: 'Error de servidor',
text: xhr.responseText || 'Error'
});
// 🔁 revertir TODOS los campos modificados
Object.keys(cambios).forEach(campo => {
grid.updateCell(args.rowIndex, campo, prev[campo]);
});
}
});
},
filterSettings: {
type: 'Excel',
// Si no te toma los textos acá, te lo ajusto a la estructura exacta de Syncfusion que estés usando
operators: {
stringOperator: [{
value: 'contains',
text: 'Contiene'
},
{
value: 'equal',
text: 'Igual'
},
{
value: 'startswith',
text: 'Empieza con'
},
{
value: 'endswith',
text: 'Termina con'
}
]
}
},
toolbar: [
'Search',
{
text: '<i class="bi bi-layout-three-columns"></i> Columnas',
tooltipText: 'Mostrar/ocultar columnas',
id: 'btnColumnas'
},
{
text: '<i class="bi bi-person-fill-add"></i> Nuevo',
tooltipText: 'Crear nuevo participante',
id: 'btnNuevo'
},
{
text: '<i class="bi bi-file-earmark-excel-fill"></i> Excel',
tooltipText: 'Exportar a Excel',
id: 'btnExcel'
}
],
toolbarClick: function(args) {
if (args.item.id === 'btnExcel') {
const hoy = new Date().toISOString().slice(0, 10);
grid.excelExport({
fileName: `participantes_${hoy}.xlsx`
});
} else if (args.item.id === 'btnColumnas') {
grid.columnChooserModule.openColumnChooser(0, 0);
} else if (args.item.id === 'btnNuevo') {
inicializarFormularioNuevoUsuario();
cambiarVista('#pantallaFormulario', '#pantallaGrilla');
}
},
disableHtmlEncode: false,
columns: [{
headerText: '',
width: 100,
template: () => `
<div class="text-center d-flex justify-content-center gap-2">
<button type="button" class="btn btn-sm btn-outline-primary btn-icon-sm btnEditar" title="Editar">
<i class="bi bi-pencil-fill"></i>
</button>
<button type="button" class="btn btn-sm btn-outline-danger btn-icon-sm btnEliminar" title="Eliminar">
<i class="bi bi-trash-fill"></i>
</button>
</div>
`,
allowSorting: false,
allowFiltering: false,
allowEditing: false
},
{
field: 'id',
headerText: '#',
width: 80,
textAlign: 'Right',
visible: false,
allowEditing: false,
isPrimaryKey: true
},
{
field: 'nombre',
headerText: 'Nombre',
width: 200,
clipMode: 'Ellipsis',
allowEditing: false
},
{
field: 'usuario',
headerText: 'Usuario',
width: 190,
visible: false,
clipMode: 'Ellipsis',
allowEditing: false
},
{
field: 'dni',
headerText: 'DNI',
width: 110,
visible: false,
allowEditing: false
},
{
field: 'email',
headerText: 'Email',
width: 220,
visible: false,
allowEditing: false
},
{
field: 'departamento',
headerText: 'Departamento',
width: 180,
allowEditing: false
},
{
field: 'fecha_bp',
headerText: 'BP fecha',
width: 140,
allowEditing: false
},
{
field: 'lugar_bp',
headerText: 'BP lugar',
width: 140,
allowEditing: false
},
{
field: 'asistencia_bp',
headerText: 'BP asiste',
width: 120,
textAlign: 'Center',
allowEditing: true,
editType: 'booleanedit',
displayAsCheckBox: true,
valueAccessor: asistenciaText
},
{
field: 'alojamiento_bp',
headerText: 'BP alojamiento',
width: 220,
clipMode: 'EllipsisWithTooltip',
allowEditing: false
},
{
field: 'fecha_b1_1',
headerText: 'B1D1 fecha',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'lugar_b1_1',
headerText: 'B1D1 lugar',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'asistencia_b1_1',
headerText: 'B1D1 asiste',
width: 120,
textAlign: 'Center',
allowEditing: true,
visible: false,
editType: 'booleanedit',
displayAsCheckBox: true,
valueAccessor: asistenciaText
},
{
field: 'fecha_b1_2',
headerText: 'B1D2 fecha',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'lugar_b1_2',
headerText: 'B1D2 lugar',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'asistencia_b1_2',
headerText: 'B1D2 asiste',
width: 120,
textAlign: 'Center',
allowEditing: true,
visible: false,
editType: 'booleanedit',
displayAsCheckBox: true,
valueAccessor: asistenciaText
},
{
field: 'alojamiento_b1',
headerText: 'B1 alojamiento',
width: 220,
visible: false,
clipMode: 'EllipsisWithTooltip',
allowEditing: false
},
{
field: 'fecha_b2_1',
headerText: 'B2D1 fecha',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'lugar_b2_1',
headerText: 'B2D1 lugar',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'asistencia_b2_1',
headerText: 'B2D1 asiste',
width: 120,
textAlign: 'Center',
allowEditing: true,
visible: false,
editType: 'booleanedit',
displayAsCheckBox: true,
valueAccessor: asistenciaText
},
{
field: 'fecha_b2_2',
headerText: 'B2D2 fecha',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'lugar_b2_2',
headerText: 'B2D2 lugar',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'asistencia_b2_2',
headerText: 'B2D2 asiste',
width: 120,
textAlign: 'Center',
allowEditing: true,
visible: false,
editType: 'booleanedit',
displayAsCheckBox: true,
valueAccessor: asistenciaText
},
{
field: 'alojamiento_b2',
headerText: 'B2 alojamiento',
width: 220,
visible: false,
clipMode: 'EllipsisWithTooltip',
allowEditing: false
},
{
field: 'fecha_b3_1',
headerText: 'B3D1 fecha',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'lugar_b3_1',
headerText: 'B3D1 lugar',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'asistencia_b3_1',
headerText: 'B3D1 asiste',
width: 120,
textAlign: 'Center',
allowEditing: true,
visible: false,
editType: 'booleanedit',
displayAsCheckBox: true,
valueAccessor: asistenciaText
},
{
field: 'fecha_b3_2',
headerText: 'B3D2 fecha',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'lugar_b3_2',
headerText: 'B3D2 lugar',
width: 160,
visible: false,
allowEditing: false
},
{
field: 'asistencia_b3_2',
headerText: 'B3D2 asiste',
width: 120,
textAlign: 'Center',
allowEditing: true,
visible: false,
editType: 'booleanedit',
displayAsCheckBox: true,
valueAccessor: asistenciaText
},
{
field: 'alojamiento_b3',
headerText: 'B3 alojamiento',
width: 220,
visible: false,
clipMode: 'EllipsisWithTooltip',
allowEditing: false
},
{
field: 'comida',
headerText: 'Comida',
width: 160,
visible: false,
allowEditing: false
}
]
});
grid.appendTo('#lstTabla');
const modalEditarParticipante = new bootstrap.Modal(
document.getElementById("modalEditarParticipante")
);
$('#lstTabla').on('click', '.btnEditar', function() {
const row = $(this).closest('tr');
const uid = row.attr('data-uid');
const rowObj = uid ? grid.getRowObjectFromUID(uid) : null;
if (!rowObj) return;
const rowData = rowObj.data;
cargarCombosModalEdicion()
.done(function() {
cargarDatosModalEdicion(rowData);
modalEditarParticipante.show();
})
.fail(function(xhr, status, error) {
console.error("Error cargando fechas:", {
status: status,
error: error,
responseText: xhr.responseText
});
Swal.fire({
icon: 'error',
title: 'Error',
text: 'No se pudieron cargar las fechas disponibles. Revisá la consola.'
});
});
});
// 👇 Delegación robusta: funciona aunque cambie el DOM interno
$('#lstTabla').on('click', '.btnEditar', function(e) {
const row = $(this).closest('tr');
const rowObj = grid.getRowObjectFromUID(row.attr('data-uid'));
if (!rowObj) return;
const rowData = rowObj.data;
console.log('Editar:', rowData);
// cargarFormularioParaEditar(rowData);
});
},
error: function(xhr, status, error) {
console.error('Error cargando datos:', status, error, xhr.responseText);
}
});
function cambiarVista(vistaMostrar, vistaOcultar) {
const $show = $(vistaMostrar).hasClass('card') ? $(vistaMostrar) : $(vistaMostrar).closest('.card');
const $hide = $(vistaOcultar).hasClass('card') ? $(vistaOcultar) : $(vistaOcultar).closest('.card');
// ✅ Si lo que “tengo que ocultar” ya está oculto, muestro directo
if ($hide.hasClass('d-none')) {
$show.removeClass('d-none aos-animate');
(AOS.refreshHard || AOS.refresh).call(AOS);
requestAnimationFrame(() => $show.addClass('aos-animate'));
return;
}
const hideEffect = ($hide.attr('data-aos') || '').toLowerCase();
const exitClass = hideEffect.includes('fade-right') ? 'aos-exit-right' : 'aos-exit-up';
const exitMs = parseInt($hide.attr('data-aos-duration'), 10) || 600;
$hide.addClass(exitClass).one('animationend', function() {
$hide.removeClass(exitClass + ' aos-animate').addClass('d-none');
$show.removeClass('d-none aos-animate');
(AOS.refreshHard || AOS.refresh).call(AOS);
requestAnimationFrame(() => $show.addClass('aos-animate'));
});
setTimeout(() => {
if (!$hide.hasClass('d-none')) {
$hide.removeClass(exitClass + ' aos-animate').addClass('d-none');
$show.removeClass('d-none aos-animate');
(AOS.refreshHard || AOS.refresh).call(AOS);
requestAnimationFrame(() => $show.addClass('aos-animate'));
}
}, exitMs + 50);
}
function inicializarFormularioNuevoUsuario() {
$('#miFormulario')[0].reset();
$('#miFormulario').removeClass('was-validated');
$('#pantallaFormulario h5')
.html('<i class="bi bi-people me-2"></i>Nuevo Participante')
.removeClass('text-warning')
.addClass('text-success');
}
document.getElementById("btnCancelar").addEventListener("click", function() {
cambiarVista('#pantallaGrilla', '#pantallaFormulario');
});
document.getElementById("miFormulario").addEventListener("submit", function(e) {
e.preventDefault();
if (!this.checkValidity()) {
this.classList.add('was-validated');
return;
}
const datos = buildPayload(this);
$.ajax({
url: "../ajax/usuarios.ajax.php",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function(resultado) {
if (resultado.respuesta === "OK") {
const estadoGrid = grid.getPersistData(); // Guarda el estado
Swal.fire({
position: 'top', // Parte superior, centrado horizontal
icon: 'success',
title: 'El registro fue guardado',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
toast: true, // sigue siendo un toast, pero en 'top' se centra
customClass: {
popup: 'swal2-toast swal2-top-center'
}
});
cambiarVista('#pantallaGrilla', '#pantallaFormulario');
// Recargar grilla manteniendo estado
$.ajax({
url: "../ajax/usuarios.ajax.php",
method: 'POST',
data: {
accion: 'LISTAR-DATOS-CURSO'
},
dataType: 'json',
success: function(data) {
grid.dataSource = data;
const estado = JSON.parse(estadoGrid);
if (estado.filterSettings) grid.filterSettings = estado.filterSettings;
if (estado.searchSettings) grid.searchSettings = estado.searchSettings;
}
});
} else {
Swal.fire({
icon: 'error',
title: 'Error al guardar',
text: resultado.mensaje,
confirmButtonText: 'Aceptar',
customClass: {
confirmButton: 'btn btn-danger',
popup: 'rounded'
},
buttonsStyling: false
});
}
}
});
});
function eliminarRegistro(rowData) {
Swal.fire({
icon: 'question',
title: '¿Está seguro?',
html: `Se eliminará el usuario <b>"${rowData.nombre}"</b>`,
showCancelButton: true,
confirmButtonText: 'Sí, borrar',
cancelButtonText: 'Cancelar',
buttonsStyling: false, // importante para usar Bootstrap
customClass: {
popup: 'my-swal-popup',
actions: 'my-swal-actions',
confirmButton: 'btn btn-sm btn-outline-danger', // igual al botón borrar
cancelButton: 'btn btn-sm btn-outline-primary', // igual al botón editar/cancelar
icon: 'my-swal-icon'
}
}).then((result) => {
if (result.isConfirmed) {
const datos = new FormData();
datos.append('accion', 'BORRAR');
datos.append('id', rowData.id);
$.ajax({
url: "../ajax/usuarios.ajax.php",
method: 'POST',
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: 'json',
success: function(respuesta) {
if (respuesta.respuesta === 'OK') {
Swal.fire({
toast: true,
position: 'top',
icon: 'success',
title: 'El registro fue eliminado',
showConfirmButton: false,
timer: 2500,
timerProgressBar: true
});
// Recargar grilla manteniendo estado
const estadoGrid = grid.getPersistData();
$.ajax({
url: "../ajax/usuarios.ajax.php",
method: 'POST',
data: {
accion: 'LISTAR-DATOS-CURSO'
},
dataType: 'json',
success: function(data) {
grid.dataSource = data;
const estado = JSON.parse(estadoGrid);
if (estado.filterSettings) grid.filterSettings = estado.filterSettings;
if (estado.searchSettings) grid.searchSettings = estado.searchSettings;
}
});
} else {
Swal.fire('Error', respuesta.mensaje, 'error');
}
}
});
}
});
}
$('#lstTabla').on('click', '.btnEliminar', function() {
const row = $(this).closest('tr');
const uid = row.attr('data-uid');
const rowObj = uid ? grid.getRowObjectFromUID(uid) : null;
if (!rowObj) return;
eliminarRegistro(rowObj.data);
});
</script>