Files
MVE/views/seguridad/agregar.php
2025-07-09 16:14:22 -06:00

479 lines
23 KiB
PHP

<?php
include __DIR__ . '/../partials/sidebar_configuracion.php';
$dos_factores_estado = obtenerEstadoDosFactores();
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>👮 Opciones de Seguridad</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/2.1.2/sweetalert.min.js"></script>
<!-- SweetAlert2 -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<!-- Animate.css para animaciones adicionales -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
<style>
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
.navbar { position: fixed; top: 0; width: 100%; z-index: 1050; }
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
/* En móviles, sin margen lateral */
@media (max-width: 767.98px) {
.content { margin-left: 0; }
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
}
.hide { display: none !important; }
.card { border-radius: 12px; }
.btn i { font-family: "Font Awesome 6 Free", sans-serif; margin-right: 0.5rem; }
.btn { font-family: 'Segoe UI', sans-serif; }
/* Fix para z-index del modal */
.modal { z-index: 9999 !important; }
.modal-backdrop { z-index: 9998 !important; }
/* Estilos adicionales para mejorar la apariencia del modal */
.modal-content { border: none; border-radius: 15px; overflow: hidden; }
.modal-header { border-bottom: none; padding: 20px 25px 15px; }
.modal-body { padding: 25px; }
.modal-footer { border-top: none; padding: 15px 25px 25px; }
.btn { border-radius: 8px; padding: 10px 20px; font-weight: 500; }
.alert-info { background-color: #e3f2fd; border-color: #bbdefb; color: #1565c0; border-radius: 8px; }
/* Animación suave para el modal */
.modal.fade .modal-dialog { transform: translate(0, -50px); transition: transform 0.3s ease-out; }
.modal.show .modal-dialog { transform: translate(0, 0); }
/* Animaciones personalizadas */
.card-hover { transition: all 0.3s ease; cursor: pointer; }
.card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
.btn-pulse { animation: pulse 2s infinite; }
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
/* Responsive animations */
@media (max-width: 768px) { .card-hover:hover { transform: translateY(-4px) scale(1.01); } }
/* Efecto de glow para elementos activos */
.btn.active { box-shadow: 0 0 20px rgba(var(--bs-primary-rgb), 0.5); }
/* Animación para el título */
.title-glow { text-shadow: 0 0 10px rgba(0, 123, 255, 0.3); }
/* Efecto para botones */
.btn-animated { transition: all 0.3s ease; position: relative; overflow: hidden; }
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
.btn-animated:hover::before { left: 100%; }
/* ========== ANIMACIONES PARA INPUTS ========== */
/* 1. Animación al hacer focus */
.form-control { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
.form-control:focus { border-color: #0d6efd; box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25), 0 0 20px rgba(13, 110, 253, 0.3); transform: translateY(-2px); }
/* 2. Animación al escribir */
.form-control:not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
/* 3. Efecto de shake en validación */
.form-control.shake { animation: shake 0.5s ease-in-out; }
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
/* 4. Floating labels con animación */
.form-floating-custom { position: relative; margin-bottom: 1.5rem; }
.form-floating-custom .form-control { padding: 1rem 0.75rem 0.5rem 0.75rem; height: auto; }
.form-floating-custom .form-label { position: absolute; top: 0.75rem; left: 0.75rem; transition: all 0.3s ease; pointer-events: none; color: #6c757d; z-index: 2; }
.form-floating-custom .form-control:focus ~ .form-label,
.form-floating-custom .form-control:not(:placeholder-shown) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; }
/* 5. Efecto de pulso en hover */
.input-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
@keyframes inputPulse {
0% { transform: scale(1); }
50% { transform: scale(1.02); }
100% { transform: scale(1); }
}
/* 6. Gradiente animado en el borde */
.input-gradient { position: relative; overflow: hidden; }
.input-gradient::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
background: linear-gradient(90deg, transparent, rgba(13, 110, 253, 0.3), transparent); transition: left 0.5s; pointer-events: none; z-index: 1; }
.input-gradient:focus::before { left: 100%; }
/* 7. Efecto de brillo en validación exitosa */
.form-control.valid { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; }
@keyframes successGlow {
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
}
/* 8. Typing effect simulation */
.input-typing { position: relative; }
.input-typing::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
.input-typing:focus::after { opacity: 1; }
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
/* 9. Efecto de ondas */
.input-ripple { position: relative; overflow: hidden; }
.input-ripple::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: rgba(13, 110, 253, 0.2);
border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
.input-ripple:focus::before { width: 300px; height: 300px; }
/* 10. Slide-up animation para los campos */
.form-group-animated { opacity: 0; transform: translateY(20px); animation: slideUp 0.6s ease-out forwards; }
.form-group-animated:nth-child(1) { animation-delay: 0.1s; }
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
.form-group-animated:nth-child(3) { animation-delay: 0.3s; }
.form-group-animated:nth-child(4) { animation-delay: 0.4s; }
.form-group-animated:nth-child(5) { animation-delay: 0.5s; }
.form-group-animated:nth-child(6) { animation-delay: 0.6s; }
.form-group-animated:nth-child(7) { animation-delay: 0.7s; }
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
</style>
</head>
<body>
<div class="content">
<h4 class="mb-4 animate__animated animate__fadeInDown title-glow">👮 Opciones de Seguridad</h4>
<div class="row g-3">
<!-- Autenticacin de dos factores -->
<div class="col-md-6 animate__animated animate__fadeInUp" style="animation-delay: 0.1s;">
<div class="card shadow-sm p-3 card-hover position-relative h-100">
<div class="card-body p-0 d-flex flex-column">
<h4 class="mb-4 text-dark">Autenticación de dos factores</h4>
<p class="text-muted small flex-grow-1 mb-4">Al activar esta funcionalidad, blindas el acceso a tu cuenta, recibiras un código de acceso a tu correo electrónico para confirmar identidad.</p>
<form method="post" action="/IMPORTADORES/seguridad/autenticacionDosFactores">
<div class="form-check form-switch mb-3">
<input type="checkbox" name="dos_factores" id="dos_factores" class="form-check-input"
<?php echo ($dos_factores_estado == 1) ? "checked" : ""; ?>>
<label class="form-check-label" for="dos_factores">
<?php echo ($dos_factores_estado == 1) ? "Activo" : "Inactivo"; ?>
</label>
</div>
<button type="submit" class="btn btn-primary btn-sm mt-2 w-40 btn-animated"><i class="fas fa-floppy-disk"></i>Guardar configuración</button>
</form>
</div>
</div>
</div>
<!-- Cambiar contraseña -->
<div class="col-md-6 animate__animated animate__fadeInUp" style="animation-delay: 0.1s;">
<div class="card shadow-sm p-3 card-hover position-relative h-100">
<div class="card-body p-0 d-flex flex-column">
<h4 class="mb-4 text-dark">Cambiar contraseña</h4>
<p class="text-muted small flex-grow-1 mb-4">Al actualizar tu contraseña, refuerzas la seguridad de tu cuenta. Te recomendamos usar una combinación de letras, números y símbolos para mayor seguridad.</p><br>
<form>
<button type="button" class="btn btn-primary btn-sm mt-2 w-40 btn-animated" data-bs-toggle="modal" data-bs-target="#modalConfirmarCambio">
<i class="fas fa-key"></i>Cambiar contraseña
</button>
</form>
</div>
</div>
</div>
<!-- Correo adicional (extra) -->
<div class="col-md-6 animate__animated animate__fadeInUp" style="animation-delay: 0.1s;">
<div class="card shadow-sm p-3 card-hover position-relative h-100">
<div class="card-body p-0 d-flex flex-column">
<h4 class="mb-4 text-dark">Recibe notificaciones</h4>
<p class="text-muted small flex-grow-1 mb-4">Agrega un correo adicional para recibir notificaciones.</p>
<?php if (!empty($correos['correo_extra'])): ?>
<p><code><?= htmlspecialchars($correos['correo_extra']) ?></code></p>
<!-- Formulario para eliminar -->
<form method="POST" action="/IMPORTADORES/seguridad/eliminarCorreoExtra" id="form-eliminar-extra" class="mt-2 hide"></form>
<form method="POST" action="/IMPORTADORES/seguridad/modificarCorreoExtra" id="formCorreoExtra">
<div class="mb-3 form-group-animated">
<div class="form-floating-custom">
<input type="email" name="email-extra" id="email_extra" class="form-control input-pulse input-typing" placeholder=" " required>
<label for="email_extra" class="form-label">Correo adicional *</label>
</div>
</div>
<div class="d-flex gap-2 form-group-animated">
<button type="submit" class="btn btn-success btn-sm mt-2 w-40 btn-animated">
<i class="fas fa-edit"></i>Actualizar
</button>
<button type="button" class="btn btn-danger btn-sm mt-2 w-40 btn-animated" onclick="confirmarEliminacion('extra')">
<i class="fas fa-trash"></i> Eliminar correo
</button>
</div>
</form>
<?php else: ?>
<form method="POST" action="/IMPORTADORES/seguridad/correoExtra" id="formCorreoExtra">
<div class="mb-3 form-group-animated">
<div class="form-floating-custom">
<input type="email" name="email-extra" id="email_extra" class="form-control input-pulse input-typing" placeholder=" " required>
<label for="email_extra" class="form-label">Correo adicional *</label>
</div>
</div>
<div class="mb-3 form-group-animated">
<button type="submit" class="btn btn-primary btn-sm mt-2 w-40 btn-animated"><i class="fas fa-envelope"></i>Registrar</button>
</div>
</form>
<?php endif; ?>
</div>
</div>
</div>
<!-- Correo de Respaldo -->
<div class="col-md-6 animate__animated animate__fadeInUp" style="animation-delay: 0.1s;">
<div class="card shadow-sm p-3 card-hover position-relative h-100">
<div class="card-body p-0 d-flex flex-column">
<h4 class="mb-4 text-dark">Correo de respaldo</h4>
<p class="text-muted small flex-grow-1 mb-4">Agrega un correo de respaldo para reuperación de tu cuenta.</p>
<?php if (!empty($correos['correo_respaldo'])): ?>
<p><code><?= htmlspecialchars($correos['correo_respaldo']) ?></code></p>
<!-- Formulario para eliminar -->
<form method="POST" action="/IMPORTADORES/seguridad/eliminarCorreoRespaldo" id="form-eliminar-respaldo" class="mt-2 hide"></form>
<form method="POST" action="/IMPORTADORES/seguridad/modificarCorreoRespaldo" id="formCorreoRespaldo">
<div class="mb-3 form-group-animated">
<div class="form-floating-custom">
<input type="email" name="email-respaldo" id="email_respaldo" class="form-control input-pulse input-typing" value="" placeholder=" " required>
<label for="email_respaldo" class="form-label">Correo de respaldo *</label>
</div>
</div>
<div class="d-flex gap-2 form-group-animated">
<button type="submit" class="btn btn-success btn-sm mt-2 w-40 btn-animated">
<i class="fas fa-edit"></i>Actualizar
</button>
<button type="button" class="btn btn-danger btn-sm mt-2 w-40 btn-animated" onclick="confirmarEliminacion('respaldo')">
<i class="fas fa-trash"></i> Eliminar correo
</button>
</div>
</form>
<?php else: ?>
<form method="POST" action="/IMPORTADORES/seguridad/correoRespaldo" id="formCorreoRespaldo">
<div class="mb-3 form-group-animated">
<div class="form-floating-custom">
<input type="email" name="email-respaldo" id="email_respaldo" class="form-control input-pulse input-typing" placeholder=" " required>
<label for="email_respaldo" class="form-label">Correo de respaldo *</label>
</div>
</div>
<div class="mb-3 form-group-animated">
<button type="submit" class="btn btn-primary btn-sm mt-2 w-40 btn-animated"><i class="fas fa-envelope"></i>Registrar</button>
</div>
</form>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<!-- Modal de confirmación -->
<div class="modal fade" id="modalConfirmarCambio" tabindex="-1" aria-labelledby="modalConfirmarCambioLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" id="modalConfirmarCambioLabel">
<i class="fas fa-exclamation-triangle me-2"></i>
Confirmar cambio de contraseña
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center">
<div class="mb-3">
<i class="fas fa-shield-alt text-warning" style="font-size: 3rem;"></i>
</div>
<h5 class="mb-3">¿Estás seguro de cambiar tu contraseña?</h5>
<p class="text-muted">
Se enviará un código de verificación a tu correo electrónico para confirmar el cambio de contraseña.
</p>
<div class="alert alert-info">
<small>
<i class="fas fa-info-circle me-1"></i>
El código expirará en 10 minutos
</small>
</div>
</div>
<div class="modal-footer justify-content-center">
<button type="button" class="btn btn-secondary btn-sm mt-2 w-40 btn-animated" data-bs-dismiss="modal">
<i class="fas fa-times me-1"></i>
Cancelar
</button>
<form method="POST" action="/IMPORTADORES/reset/enviarCodigoInterno" style="display: inline;">
<button type="submit" class="btn btn-primary btn-sm mt-2 w-40 btn-animated">
<i class="fas fa-check me-1"></i>
Sí, estoy seguro
</button>
</form>
</div>
</div>
</div>
</div>
<script>
const chk = document.getElementById('dos_factores');
const label = document.querySelector('label[for="dos_factores"]');
chk.addEventListener('change', () => { label.textContent = chk.checked ? 'Activo' : 'Inactivo'; });
// Función para confirmar eliminación con SweetAlert2
function confirmarEliminacion(tipo) {
const mensajes = {
'extra': {
titulo: '¿Eliminar correo adicional?',
texto: 'No podrás recibir notificaciones en este correo.',
confirmado: 'Correo adicional eliminado',
form: 'form-eliminar-extra'
},
'respaldo': {
titulo: '¿Eliminar correo de respaldo?',
texto: 'No podrás recuperar tu cuenta con este correo.',
confirmado: 'Correo de respaldo eliminado',
form: 'form-eliminar-respaldo'
}
};
const config = mensajes[tipo];
Swal.fire({
title: config.titulo,
text: config.texto,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#dc3545',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Sí, eliminar',
cancelButtonText: 'Cancelar',
reverseButtons: true
}).then((result) => {
if (result.isConfirmed) {
// Mostrar mensaje de éxito
Swal.fire({
title: '¡Eliminado!',
text: config.confirmado,
icon: 'success',
timer: 1500,
showConfirmButton: false
}).then(() => {
// Enviar el formulario después del mensaje
document.getElementById(config.form).submit();
});
}
});
}
// Versión simplificada sin el mensaje de confirmación extra
function confirmarEliminacionSimple(tipo) {
const mensajes = {
'extra': {
titulo: '¿Eliminar correo adicional?',
texto: 'No podrás recibir notificaciones en este correo.',
form: 'form-eliminar-extra'
},
'respaldo': {
titulo: '¿Eliminar correo de respaldo?',
texto: 'No podrás recuperar tu cuenta con este correo.',
form: 'form-eliminar-respaldo'
}
};
const config = mensajes[tipo];
Swal.fire({
title: config.titulo,
text: config.texto,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#dc3545',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Sí, eliminar',
cancelButtonText: 'Cancelar',
reverseButtons: true
}).then((result) => {
if (result.isConfirmed) {
// Enviar el formulario directamente
document.getElementById(config.form).submit();
}
});
}
// Limpiar y consolidar los event listeners
document.addEventListener('DOMContentLoaded', function() {
// Event listener único para correo extra
const formCorreoExtra = document.getElementById('formCorreoExtra');
if (formCorreoExtra) {
formCorreoExtra.addEventListener('submit', function(e) {
e.preventDefault();
const correo_extra = document.getElementById('email_extra').value.trim();
const correoRegex = /^[a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!correoRegex.test(correo_extra)) {
Swal.fire({
icon: 'error',
title: 'Correo inválido',
text: 'No es una dirección de correo válida.',
confirmButtonColor: '#dc3545'
});
document.getElementById('email_extra').focus();
return;
}
// Si la validación pasa, enviar el formulario
this.submit();
});
}
// Event listener único para correo de respaldo
const formCorreoRespaldo = document.getElementById('formCorreoRespaldo');
if (formCorreoRespaldo) {
formCorreoRespaldo.addEventListener('submit', function(e) {
e.preventDefault();
const correo_respaldo = document.getElementById('email_respaldo').value.trim();
const correoRegex = /^[a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!correoRegex.test(correo_respaldo)) {
Swal.fire({
icon: 'error',
title: 'Correo inválido',
text: 'No es una dirección de correo válida.',
confirmButtonColor: '#dc3545'
});
document.getElementById('email_respaldo').focus();
return;
}
// Si la validación pasa, enviar el formulario
this.submit();
});
}
// Animaciones de validación
const inputs = document.querySelectorAll('.form-control');
inputs.forEach(input => {
input.addEventListener('input', function() {
if (this.checkValidity()) {
this.classList.remove('shake');
this.classList.add('valid');
} else {
this.classList.remove('valid');
}
});
input.addEventListener('invalid', function() {
this.classList.add('shake');
setTimeout(() => {
this.classList.remove('shake');
}, 500);
});
});
});
</script>
</body>
</html>