File: /var/www/vhost/disk-apps/alq-cali.bikenow.co/resources/views/web_experiences/enroll/js.blade.php
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/intlTelInput.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js"></script>
<script>
const loginInput = document.getElementById('loginInput');
const loginButton = document.getElementById('loginSubmitBtn');
const registerSubmitBtn = document.getElementById('registerSubmitBtn');
function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function isValidDocument(doc) {
return /^[0-9]{5,20}$/.test(doc); // ajusta la expresión si tus documentos tienen letras o un rango diferente
}
function showForm(type) {
// Mostrar/Ocultar formularios
document.getElementById('form-registered').style.display = (type === 'registered') ? 'block' : 'none';
document.getElementById('form-new-user').style.display = (type === 'new') ? 'block' : 'none';
// Activar botón correspondiente
document.getElementById('btn-registered').classList.toggle('active', type === 'registered');
document.getElementById('btn-new').classList.toggle('active', type === 'new');
}
let participantCount = 1;
function checkParticipantLimit() {
let enableParticipants = false;
if (document.getElementById('enable_raffle')) {
const enableRaffleValue = document.getElementById('enable_raffle').value;
enableParticipants = enableRaffleValue === 'false' || enableRaffleValue === '0';
}
const addBtn = document.getElementById('addParticipantBtn');
const enrollSubmitBtn = document.getElementById('enrollSubmitBtn');
if (enableParticipants) {
let entriesPerPurchase = 1;
if (document.getElementById('entries_per_purchase')) {
entriesPerPurchase = (parseInt(document.getElementById('entries_per_purchase').value) || 1) * (parseInt(document.getElementById('amount').value) || 1);
}
const maxParticipants = entriesPerPurchase;
let currentCount = 1;
if (document.getElementById('participants-container')) {
currentCount = document.getElementById('participants-container')
.querySelectorAll('.participant-block').length;
}
if (currentCount >= maxParticipants && addBtn && enrollSubmitBtn) {
addBtn.style.display = 'none';
enrollSubmitBtn.disabled = false;
enrollSubmitBtn.classList.toggle('active', true);
} else if (enrollSubmitBtn) {
enrollSubmitBtn.disabled = true;
enrollSubmitBtn.classList.toggle('active', false);
}
} else {
if (addBtn && enrollSubmitBtn) {
addBtn.style.display = 'none';
enrollSubmitBtn.disabled = false;
enrollSubmitBtn.classList.toggle('active', true);
}
}
}
function addParticipant() {
let entriesPerPurchase = 1;
if (document.getElementById('entries_per_purchase')) {
entriesPerPurchase = (parseInt(document.getElementById('entries_per_purchase').value) || 1) * (parseInt(document.getElementById('amount').value) || 1);
}
const maxParticipants = entriesPerPurchase;
const container = document.getElementById('participants-container');
const currentCount = container.querySelectorAll('.participant-block').length;
if (currentCount >= maxParticipants && document.getElementById('addParticipantBtn')) {
document.getElementById('addParticipantBtn').style.display = 'none';
return;
}
participantCount++;
const original = container.querySelector('.participant-block');
const clone = original.cloneNode(true);
// Cambiar título
clone.querySelectorAll(".form-participant-header").forEach(group => {
group.querySelectorAll('p').forEach(p => {
p.remove(); // Eliminar el párrafo del DOM
});
group.querySelector('h3').innerText = 'Participante ' + participantCount;
});
clone.querySelectorAll(".form-group").forEach(group => {
group.hidden = false; // Mostrar todos los campos
});
clone.querySelector('#editBuyerData').hidden = true; // Ocultar checkbox de edición
// Cambiar el nombre de los inputs
clone.querySelectorAll('input').forEach(input => {
const name = input.getAttribute('name');
if (name && name.startsWith('buyer_')) {
input.setAttribute('name', name.replace('buyer_', 'companion' + participantCount + '_'));
}
if (name && name.includes('phone')) {
if (!name.includes('code')) {
const iti = window.intlTelInput(input, {
initialCountry: "co", // o "auto" con geoIpLookup si deseas detección automática
preferredCountries: ["co", "us", "pa", "ec", "cl"], // Países preferidos
separateDialCode: true, // Esto separa el indicativo del número
utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js",
});
const dialCodeInput = clone.querySelector('input[name="companion' + participantCount + '_dial_code"]');
const countryCodeInput = clone.querySelector('input[name="companion' + participantCount + '_country_code"]');
if (dialCodeInput) {
dialCodeInput.value = iti.getSelectedCountryData().dialCode;
}
if (countryCodeInput) {
countryCodeInput.value = iti.getSelectedCountryData().iso2;
}
input.addEventListener('countrychange', function() {
dialCodeInput.value = iti.getSelectedCountryData().dialCode;
countryCodeInput.value = iti.getSelectedCountryData().iso2;
});
}
}
// Limpiar el valor del input
input.value = '';
});
clone.querySelectorAll('select').forEach(select => {
const name = select.getAttribute('name');
if (name) {
select.setAttribute('name', name.replace('buyer_', 'companion' + participantCount + '_'));
}
// Limpiar la selección
select.selectedIndex = 0;
});
container.appendChild(clone);
// Revalidar límite
checkParticipantLimit();
}
function waitForOtpVerification(email, form) {
return new Promise((resolve, reject) => {
const modal = document.getElementById('otpModal');
const input = document.getElementById('otpInput');
const errorDiv = document.getElementById('otpError');
const button = document.getElementById('verifyOtpBtn');
const closeBtn = document.getElementById('closeOtpModal');
// Mostrar modal
modal.style.display = 'flex';
input.value = '';
errorDiv.textContent = '';
button.disabled = true;
input.focus();
// Cerrar modal
closeBtn.onclick = () => {
modal.style.display = 'none';
reject(new Error("Verificación cancelada."));
};
// Validar cantidad de dígitos
input.addEventListener('input', () => {
button.disabled = input.value.trim().length !== 6;
});
button.onclick = async () => {
const code = input.value.trim();
if (code.length !== 6) {
errorDiv.textContent = "Debes ingresar 6 dígitos.";
return;
}
errorDiv.textContent = "Verificando...";
button.disabled = true;
try {
const response = await fetch("{{ route('otp.verify') }}", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": form.querySelector('input[name="_token"]').value,
},
body: JSON.stringify({
code,
email
})
});
const data = await response.json();
if (!response.ok || data.status !== 'success') {
errorDiv.textContent = data.message || "Código de validación inválido.";
button.disabled = false;
return;
}
modal.style.display = 'none';
resolve(); // Continuar login
} catch (err) {
errorDiv.textContent = "Error de conexión. Intenta de nuevo.";
button.disabled = false;
}
};
});
}
async function resendCode() {
const input = document.getElementById('otpInput');
const errorDiv = document.getElementById('otpError');
const email = document.querySelector('input[name="login"]')?.value;
if (!email) {
errorDiv.textContent = "No se puede reenviar el código porque falta el correo.";
return;
}
errorDiv.textContent = "Enviando nuevo código...";
try {
const response = await fetch("{{ route('otp.generate') }}", {
method: "POST",
headers: {
"X-CSRF-TOKEN": document.querySelector('input[name="_token"]').value
},
body: new URLSearchParams({
email
})
});
const data = await response.json();
if (!response.ok || data.status !== 'success') {
errorDiv.textContent = data.message || "No se pudo reenviar el código.";
return;
}
errorDiv.textContent = "Se envió un nuevo código a tu correo.";
input.value = '';
document.getElementById('verifyOtpBtn').disabled = true;
input.focus();
} catch (err) {
errorDiv.textContent = "Error al reenviar el código.";
}
}
toggleEditParticipantData = () => {
document.querySelectorAll('.form-group').forEach(group => {
group.hidden = !group.hidden;
});
}
// Verificar al cargar la página
document.addEventListener('DOMContentLoaded', function() {
checkParticipantLimit();
// Solo letras y espacios
document.querySelectorAll('.only-letters').forEach(input => {
input.addEventListener('input', () => {
input.value = input.value.replace(/[^A-Za-zÁÉÍÓÚáéíóúÑñ\s]/g, '');
});
});
// Solo números
document.querySelectorAll('.only-numbers').forEach(input => {
input.addEventListener('input', () => {
input.value = input.value.replace(/[^0-9]/g, '');
});
});
// Solo alfanumérico
document.querySelectorAll('.only-alphanum').forEach(input => {
input.addEventListener('input', () => {
input.value = input.value.replace(/[^A-Za-z0-9]/g, '');
});
});
document.querySelectorAll('select[name$="_document_type_id"]').forEach(select => {
select.addEventListener('change', function() {
const prefix = this.name.replace('_document_type_id', '');
const documentInput = document.querySelector(`input[name="${prefix}_document"]`);
if (documentInput) {
if (this.value) {
documentInput.disabled = false;
documentInput.setAttribute('required', 'required');
} else {
documentInput.disabled = true;
documentInput.value = '';
documentInput.removeAttribute('required');
}
}
});
});
document.querySelectorAll('input[name="confirm_email"]').forEach(confirmInput => {
const container = confirmInput.closest('.form-group').parentNode;
const emailInput = container.querySelector('input[name="email"]');
const errorSpan = confirmInput.parentNode.querySelector('.error-message');
function validateEmails() {
const emailValue = emailInput.value.trim();
const confirmValue = confirmInput.value.trim();
if (emailValue && confirmValue && emailValue !== confirmValue) {
errorSpan.style.display = 'inline';
confirmInput.setCustomValidity("Los correos electrónicos no coinciden.");
} else {
errorSpan.style.display = 'none';
confirmInput.setCustomValidity("");
}
}
// Validar al escribir o salir del campo
confirmInput.addEventListener('input', validateEmails);
emailInput.addEventListener('input', validateEmails);
});
if (document.getElementById('enroll-form')) {
document.getElementById('enroll-form').addEventListener('submit', function(e) {
e.preventDefault(); // Evita que recargue
const form = e.target;
const url = form.action;
const formData = new FormData(form);
const submitButton = form.querySelector('button[type="submit"]');
submitButton.disabled = true; // Deshabilitar botón para evitar múltiples envíos
submitButton.classList.add('loading'); // Agregar clase de carga
const originalText = submitButton.textContent; // Guardar texto original
submitButton.textContent = 'Procesando... ⏳'; // opcional
fetch(url, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json',
}
})
.then(async response => {
const data = await response.json();
if (!response.ok) {
// Mostrar errores de validación con Swal
if (data.errors) {
const allErrors = Object.values(data.errors)
.flat()
.join('<br>');
throw new Error(allErrors);
} else {
throw new Error('Ocurrió un error al procesar tu inscripción. Inténtalo de nuevo más tarde.');
}
}
// Éxito
if (data.redirect) {
window.location.href = data.redirect;
} else {
Swal.fire({
icon: 'success',
title: 'Inscripción exitosa',
text: data.message || 'Te has inscrito correctamente.',
showConfirmButton: true,
confirmButtonText: 'Aceptar',
confirmButtonColor: '<?php echo $corporateIdentity->btnBox_color; ?>',
allowOutsideClick: false,
allowEscapeKey: false,
allowEnterKey: false
}).then(() => {
// Recargar la página o redirigir
window.location.href = "/web_experiences";
});
}
})
.then(data => {
if (data && data.redirect) {
window.location.href = data.redirect;
}
})
.catch(error => {
console.error(error);
Swal.fire({
icon: 'error',
title: 'Error',
text: error || "Ocurrio un error inesperado.",
showConfirmButton: true,
confirmButtonText: 'Aceptar',
confirmButtonColor: '<?php echo $corporateIdentity->btnBox_color; ?>',
allowOutsideClick: false,
allowEscapeKey: false,
allowEnterKey: false
});
submitButton.disabled = false; // Rehabilitar botón
submitButton.classList.remove('loading'); // Quitar clase de carga
submitButton.textContent = originalText; // Restaurar texto original
});
});
}
if (document.getElementById('closeUserBtn')) {
document.getElementById('closeUserBtn').addEventListener('click', function() {
Swal.fire({
title: 'Alerta',
text: '¿Deseas quitar este participante?',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, quitar participante',
cancelButtonText: 'Cancelar',
confirmButtonColor: '<?php echo $corporateIdentity->btnBox_color; ?>',
cancelButtonColor: '#6c757d',
reverseButtons: true,
allowOutsideClick: false,
allowEscapeKey: false,
allowEnterKey: false
}).then((result) => {
if (result.isConfirmed) {
fetch("{{ route('web_experiences.logout') }}", {
method: "POST",
headers: {
"X-CSRF-TOKEN": "{{ csrf_token() }}",
"Accept": "application/json",
"Content-Type": "application/json"
}
}).then(() => {
location.reload();
}).catch(() => {
Swal.fire('Error', 'No se pudo cerrar sesión.', 'error');
});
}
});
});
}
const form = document.getElementById('form-new-user');
if (!form) return; // Asegurarse de que el formulario existe
const submitButton = form.querySelector('.register-btn-new-user');
const checkFormValidity = () => {
if (form.checkValidity()) {
submitButton.disabled = false;
submitButton.classList.toggle('active', true);
} else {
submitButton.disabled = true;
submitButton.classList.toggle('active', false);
}
};
// Escuchar eventos en todos los inputs, selects y textareas
const inputs = form.querySelectorAll('input, select, textarea');
inputs.forEach(input => {
input.addEventListener('input', checkFormValidity);
input.addEventListener('change', checkFormValidity);
});
// Validación inicial por si ya hay datos precargados
checkFormValidity();
});
if (loginInput) {
loginInput.addEventListener('input', function() {
const value = loginInput.value.trim();
if (isValidEmail(value)) {
loginButton.disabled = false;
loginButton.classList.toggle('active', true);
} else {
loginButton.disabled = true;
loginButton.classList.toggle('active', false);
}
});
}
if (document.getElementById('form-registered')) {
document.getElementById('form-registered').addEventListener('submit', async function(e) {
e.preventDefault(); // Evita recarga
const form = e.target;
const formData = new FormData(form);
const errorDiv = document.getElementById('login-error');
errorDiv.textContent = ''; // Limpia errores previos
const submitButton = form.querySelector('button[type="submit"]');
submitButton.disabled = true;
submitButton.classList.add('loading');
const originalText = submitButton.textContent;
submitButton.textContent = 'Enviando código... ⏳';
try {
// 1. Paso: Generar OTP
const otpFormData = new FormData();
otpFormData.append('email', formData.get('login') || '');
const otpResponse = await fetch("{{ route('otp.generate') }}", {
method: "POST",
headers: {
"X-CSRF-TOKEN": form.querySelector('input[name="_token"]').value,
"Accept": "application/json"
},
body: otpFormData
});
if (!otpResponse.ok) {
const errorData = await otpResponse.json();
throw new Error(errorData.message || "No se pudo generar el código de validación.");
}
const otpData = await otpResponse.json();
if (otpData.status !== 'success') {
throw new Error(otpData.message || "Error al generar código.");
}
// 2. Mostrar modal OTP y esperar verificación
await waitForOtpVerification(formData.get('login'), form);
// 4. Si OTP válido, proceder al login
submitButton.textContent = 'Validando acceso... ⏳';
const loginResponse = await fetch("{{ route('login.by.document.or.email') }}", {
method: "POST",
headers: {
"X-CSRF-TOKEN": form.querySelector('input[name="_token"]').value,
"Accept": "application/json"
},
body: formData
});
if (!loginResponse.ok) {
const errorData = await loginResponse.json();
throw new Error(errorData.message || "Error en la autenticación.");
}
const loginData = await loginResponse.json();
if (loginData.success) {
window.location.href = loginData.redirect || "{{ url()->current() }}";
} else {
throw new Error(loginData.message || "Acceso denegado.");
}
} catch (error) {
console.error(error);
errorDiv.textContent = error.message || "Ocurrió un error inesperado.";
submitButton.disabled = false;
submitButton.classList.remove('loading');
submitButton.textContent = originalText;
}
});
}
if (document.getElementById('form-new-user')) {
document.getElementById('form-new-user').addEventListener('submit', async function(e) {
e.preventDefault(); // Evita recarga
if (!isValidPhoneNumber()) {
Swal.fire({
icon: 'error',
title: 'Número de teléfono inválido',
text: 'Por favor, ingresa un número de teléfono válido.',
showConfirmButton: true,
confirmButtonText: 'Aceptar',
confirmButtonColor: '<?php echo $corporateIdentity->btnBox_color; ?>',
allowOutsideClick: false,
allowEscapeKey: false,
allowEnterKey: false
});
return;
}
const form = e.target;
const formData = new FormData(form);
const errorDiv = document.getElementById('register-error');
errorDiv.textContent = ''; // Limpia errores previos
const submitButton = form.querySelector('button[type="submit"]');
submitButton.disabled = true; // Deshabilitar botón para evitar múltiples envíos
submitButton.classList.add('loading'); // Agregar clase de carga
const originalText = submitButton.textContent; // Guardar texto original
submitButton.textContent = 'Enviando código... ⏳';
try {
// 1. Paso: Generar OTP
const otpFormData = new FormData();
otpFormData.append('email', formData.get('email') || '');
const otpResponse = await fetch("{{ route('otp.generate') }}", {
method: "POST",
headers: {
"X-CSRF-TOKEN": form.querySelector('input[name="_token"]').value,
"Accept": "application/json"
},
body: otpFormData
});
if (!otpResponse.ok) {
const errorData = await otpResponse.json();
throw new Error(errorData.message || "No se pudo generar el código de validación.");
}
const otpData = await otpResponse.json();
if (otpData.status !== 'success') {
throw new Error(otpData.message || "Error al generar código.");
}
// 2. Mostrar modal OTP y esperar verificación
await waitForOtpVerification(formData.get('email'), form);
// 4. Si OTP válido, proceder al registro
submitButton.textContent = 'Validando registro... ⏳';
const registerResponse = await fetch("{{ route('register.new.user') }}", {
method: "POST",
headers: {
"X-CSRF-TOKEN": form.querySelector('input[name="_token"]').value,
"Accept": "application/json"
},
body: formData
});
if (!registerResponse.ok) {
const errorData = await registerResponse.json();
throw new Error(errorData.message || "Error en el registro.");
}
const registerData = await registerResponse.json();
if (registerData.success) {
window.location.href = registerData.redirect || "{{ url()->current() }}";
} else {
throw new Error(registerData.message || "Registro denegado.");
}
} catch (error) {
console.error(error);
Swal.fire({
icon: 'error',
title: 'Error en la solicitud',
text: error.message || data.message || "Error de conexión. Intente de nuevo.",
showConfirmButton: true,
confirmButtonText: 'Aceptar',
confirmButtonColor: '<?php echo $corporateIdentity->btnBox_color; ?>',
allowOutsideClick: false,
allowEscapeKey: false,
allowEnterKey: false
});
errorDiv.textContent = error.message || "Ocurrió un error inesperado.";
submitButton.disabled = false;
submitButton.classList.remove('loading');
submitButton.textContent = originalText;
}
});
}
$(document).ready(function() {
function formatCurrency(value) {
return new Intl.NumberFormat('es-CO', {
style: 'currency',
currency: <?php echo json_encode($corporateIdentity->currency); ?>,
currencyDisplay: 'narrowSymbol',
minimumFractionDigits: <?php echo json_encode($corporateIdentity->minimum_fraction_digits); ?>,
maximumFractionDigits: <?php echo json_encode($corporateIdentity->maximum_fraction_digits); ?>,
}).format(value);
}
$('.plan-price').each(function() {
let amountText = $(this).text();
let formatted = formatCurrency(amountText);
$(this).text(formatted);
});
});
const dialCodeInput = document.querySelector("#dial-code");
const countryCodeInput = document.querySelector("#country-code");
const phoneInput = document.querySelector("#phone");
let iti;
if (phoneInput) {
iti = window.intlTelInput(phoneInput, {
initialCountry: "co", // o "auto" con geoIpLookup si deseas detección automática
preferredCountries: ["co", "us", "pa", "ec", "cl"], // Países preferidos
separateDialCode: true, // Esto separa el indicativo del número
utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js",
});
}
// Establecer el valor inicial al cargar
if (dialCodeInput) {
dialCodeInput.value = dialCode();
}
if (countryCodeInput) {
countryCodeInput.value = countryCode();
}
if (phoneInput) {
phoneInput.addEventListener('countrychange', function() {
dialCodeInput.value = dialCode();
countryCodeInput.value = countryCode();
});
}
function dialCode() {
return iti.getSelectedCountryData().dialCode;
}
function countryCode() {
return iti.getSelectedCountryData().iso2;
}
function isValidPhoneNumber() {
return iti.isValidNumber();
}
</script>