$.ajaxSetup({ headers: { 'Authorization': 'Bearer ', 'X-User-Token': 'es', } }); if(axios) { axios.defaults.headers.common['X-User-Lang'] = 'es'; axios.defaults.headers.common['Authorization'] = 'Bearer '; } const AppInstance = function() { this.auth = { signIn: false, user: {"cl_pueblo": ""} } this.authToken = ''; this.baseUrl = 'https://tulicenciapr.com/'; this.baseApiUrl = 'https://api.tulicenciapr.com:2053/api'; } AppInstance.prototype = { route: function(uri, params = {}) { return route(uri, params); }, apiUrl: function(uri) { return `${this.baseApiUrl}${uri}` }, getStepItem: function (name, def = null, formIndex = 0) { var nameKey = `stepForm-${formIndex}-${name}` return localStorage.getItem(nameKey) ? localStorage.getItem(nameKey) : def; }, setStepItem: function (name, value = '', formIndex = 0) { var nameKey = `stepForm-${formIndex}-${name}` localStorage.setItem(nameKey, _.toString(value)); } } window['App'] = new AppInstance(); const TranslatorInstance = function() { this.lang = 'es'; this.translations = []; this.load(); } TranslatorInstance.prototype = { load: function () { var self = this; axios.get(`https://api.tulicenciapr.com:2053/api/Translation/Json/es?`) .then(function(response) { self.translations = response.data; }) }, replaceArgs: function(template, args) { return template.replace(/\{(\d+)\}/g, function(match, index) { return args[index] !== undefined ? args[index] : match; }) }, translate: function(name, trans = '', args = []) { if (Array.isArray(trans)) { args = trans; trans = undefined; } const value = this.translations[name.toLowerCase()] ?? trans ?? name; var text = typeof value === "string" && value.includes("::") ? value.split("::")[1] : value; return this.replaceArgs(text, args); }, t: function(name, trans = '', args = []) { return this.translate(name, trans, args); } } window['Translator'] = new TranslatorInstance(); /** * Validaciones */ $.validator.methods.email = function (value, element) { return this.optional(element) || /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/.test(value); }; $.validator.addMethod("license-number", function (value, element) { return this.optional(element) || /^[A-Za-z0-9]+$/.test(value); }, 'La licencia solo puede contener letras y números, sin espacios ni símbolos.'); $.extend($.validator.messages, { required: 'Este campo es requerido', email: 'Ingrese un correo electrónico válido', numbers: 'Solo se permiten números', minlength: $.validator.format('El campo no puede tener menos de {0} caracteres'), maxlength: $.validator.format('El campo no puede tener más de {0} caracteres'), equalTo: 'Ingrese el mismo valor de nuevo', digits: 'Solo se permiten dígitos', letters: 'Solo se permiten letras', range: $.validator.format('El valor debe estar entre {0} y {1}'), max: $.validator.format('El valor máximo del campo es {0}'), min: $.validator.format('El valor mínimo del campo es {0}'), phone: 'Formato de teléfono inválido. Ej: (999) 999-9994', username: 'Solo se permiten letras, números y guiones bajos', password: 'La contraseña debe contener al menos 8 caracteres, una letra mayúscula, un número y un carácter especial.', card: 'Ingrese un número de tarjeta válido (Visa, MasterCard, Amex, etc.).', 'email-exists': 'Este correo ingresado ya se encuentrado registrado.', 'username-exists': 'El usuario ingresado ya existe en nuestros registros.', 'min-age': 'No cumples con la edad mínima requerida.', }); const phoneFormat = function(value) { if (!value) return value; const phoneNumber = value.replace(/[^\d]/g, ""); const phoneNumberLength = phoneNumber.length; if (phoneNumberLength < 4) { return phoneNumber } if (phoneNumberLength < 7) { return `(${phoneNumber.slice(0, 3)}) ${phoneNumber.slice(3)}`; } return `(${phoneNumber.slice(0, 3)}) ${phoneNumber.slice(3, 6)}-${phoneNumber.slice(6, 10)}`; } const detectCardType = function (numero) { const value = numero.replace(/\D/g, ''); // eliminar espacios o guiones const cardPatterns = { visa: /^4\d{0,15}$/, mastercard: /^(5[1-5]|2[2-7])\d{0,14}$/, amex: /^3[47]\d{0,13}$/, discover: /^6(?:011|5)/, diners: /^3(?:0[0-5]|[68])/, jcb: /^(?:2131|1800|35)/ }; for (let tipo in cardPatterns) { if (cardPatterns[tipo].test(value)) { return tipo; } } return null; } $('input[data-rule-phone="true"]').on('input', function(e) { $(this).val(phoneFormat(e.currentTarget.value)); }); $('input[data-rule-card="true"]').on('input', function(e) { const numberCard = $(this).val(); const typeCard = detectCardType(numberCard); const $output = $(this).closest('.input-group').find('.input-icon'); if (typeCard) { $output.html(`Tarjeta`); } else { $output.html(`Tarjeta`); } }); $.validator.addMethod("numbers", function(value, element) { return this.optional(element) || /^[0-9]+$/.test(value); }); $.validator.addMethod("letters", function(value, element) { return this.optional(element) || /^[a-zA-ZáéíóúÁÉÍÓÚñÑ\s]+$/.test(value); }); $.validator.addMethod("phone", function(value, element) { return this.optional(element) || /^\(\d{3}\)\s\d{3}-\d{4}$/.test(value); }); $.validator.addMethod("username", function (value, element) { return this.optional(element) || /^[A-Za-z0-9_]+$/.test(value); }); $.validator.addMethod("password", function (value, element) { return this.optional(element) || /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$/.test(value); }); $.validator.addMethod("card", function (value, element) { if (this.optional(element)) return true; // Eliminar espacios y guiones value = value.replace(/[\s-]/g, ''); // Validar solo números if (!/^\d+$/.test(value)) return false; // Tipos de tarjeta comunes (regex) const cardPatterns = { visa: /^4\d{12}(?:\d{3})?$/, // 13 o 16 dígitos mastercard: /^5[1-5]\d{14}|^2[2-7]\d{14}$/, // MasterCard 51–55 o 2221–2720 amex: /^3[47]\d{13}$/, // American Express discover: /^6(?:011|5\d{2})\d{12}$/, // Discover diners: /^3(?:0[0-5]|[68]\d)\d{11}$/, // Diners Club jcb: /^(?:2131|1800|35\d{3})\d{11}$/ // JCB }; // Comprobar coincidencia con algún tipo let isValidType = false; for (let key in cardPatterns) { if (cardPatterns[key].test(value)) { isValidType = true; break; } } if (!isValidType) return false; // Validar con algoritmo Luhn let sum = 0; let shouldDouble = false; for (let i = value.length - 1; i >= 0; i--) { let digit = parseInt(value.charAt(i), 10); if (shouldDouble) { digit *= 2; if (digit > 9) digit -= 9; } sum += digit; shouldDouble = !shouldDouble; } return (sum % 10) === 0; }); $.validator.addMethod("email-exists", function(value, element, param) { let isValid = false; $.ajax({ url: `https://api.tulicenciapr.com:2053/api/Usuario/ListarCorreos?query=${value}`, type: "GET", dataType: "json", async: false, success: function(response) { isValid = response.length === 0; }, error: function() { isValid = false; } }); return isValid; }); $.validator.addMethod("username-exists", function(value, element, param) { let isValid = false; $.ajax({ url: `https://api.tulicenciapr.com:2053/api/Usuario/ListarUsuarios?query=${value}`, type: "GET", dataType: "json", async: false, success: function(response) { isValid = response.length === 0; }, error: function() { isValid = false; } }); return isValid; }); $.validator.addMethod("min-age", function (value, element, param) { if (!value) return false; const inputDate = new Date(value); const today = new Date(); let age = today.getFullYear() - inputDate.getFullYear(); const monthDiff = today.getMonth() - inputDate.getMonth(); const dayDiff = today.getDate() - inputDate.getDate(); if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) { age--; } return age >= parseInt(param); }); /** ** * */ $('[name="licenseCategory"]').on('change', function(e) { var licenseCategory = $(this).val(); var $vehicleType = $('[name="vehicleType"]'); $vehicleType.closest('.field').toggleClass('!hidden', licenseCategory !== 'Chofer'); if(licenseCategory !== 'Chofer') { $vehicleType.val(''); } }); $('[name="identificationType"]').on('change', function() { var identificationType = $(this).val(); if(identificationType === 'Seguro Social') { $('[name="identificationNumber"]').attr('maxlength', 4); $('[name="identificationNumber"]').attr('readonly', 'true'); $('[name="identificationNumber"]').val(App.auth.user.cl_numeroSeguro); $('[name="identificationNumber"]').val(App.auth.user.cl_numeroSeguro); App.setStepItem('identificationNumber', App.auth.user.cl_numeroSeguro) } else { $('[name="identificationNumber"]').attr('maxlength', 9); $('[name="identificationNumber"]').removeAttr('readonly'); $('[name="identificationNumber"]').val(''); App.setStepItem('identificationNumber') } }); $('[name="addressResidential"]').on('change', function() { $('#addressResidentialContainer').toggleClass('hidden', $(this).val() === 'Sí'); }); $(document).ready(function() { $(`[name="licenseCategory"]`).val(App.getStepItem('licenseCategory', 'Conductor')).trigger('change'); $(`[name="identificationType"][value="${App.getStepItem('identificationType', 'Seguro Social')}"]`).prop('checked', true).trigger('change'); $(`[name="identificationNumber"]`).val(App.getStepItem('identificationNumber')); $('[name="licenseNumber"]').val(App.auth.user.cl_numeroLicencia); $('[name="town"]').val(App.auth.user.cl_pueblo.pl_id).trigger('change'); $('[name="zip"]').val(App.auth.user.cl_zip).trigger('change'); $('#addressResidentialContainer').toggleClass('hidden', $('[name="addressResidential"]').val() === 'No'); });