u003c!u002du002d ===== INVITAMOS DIGITAL · Form Demo (Divi Code Module) ===== u002du002du003enu003clinkn rel=u0022stylesheetu0022n href=u0022https://cdn.jsdelivr.net/npm/intl-tel-input@23.6.0/build/css/intlTelInput.min.cssu0022n/u003ennu003cstyleu003en .inv-demo * {n box-sizing: border-box;n }n .inv-demo {n u002du002dbg: #fff;n u002du002dtext: #1b1b1b;n u002du002dmuted: #747474;n u002du002dline: #e8e8e8;n u002du002dpill: #f5f5f5;n u002du002dfocus: #111;n u002du002daccent: #18a999;n u002du002derr: #b00020;n u002du002derr-bg: #fff7f8;n u002du002derr-line: #f3c2c8;n u002du002dok: #127a5e;n u002du002dinfo: #b26a00;n font-family: inherit;n color: var(u002du002dtext);n max-width: 680px;n margin-inline: auto;n }n .inv-demo fieldset {n border: 0;n margin: 0 0 18px;n padding: 0;n }n .inv-demo legend {n font-weight: 600;n margin: 6px 0 10px;n }n .inv-demo select,n .inv-demo input[type=u0022textu0022],n .inv-demo input[type=u0022telu0022] {n width: 100%;n background: var(u002du002dpill);n border: 1px solid var(u002du002dline);n border-radius: 12px;n padding: 12px 14px;n outline: none;n transition: box-shadow 0.15s ease, border-color 0.15s ease;n }n .inv-demo select:focus,n .inv-demo input:focus {n border-color: var(u002du002dfocus);n box-shadow: 0 0 0 2px #00000014;n }n .inv-demo .grid-2 {n display: grid;n grid-template-columns: 1fr 1fr;n gap: 12px;n }n @media (max-width: 700px) {n .inv-demo .grid-2 {n grid-template-columns: 1fr;n }n }n .inv-demo .file-row {n display: flex;n gap: 12px;n align-items: center;n flex-wrap: wrap;n }n .inv-demo input[type=u0022fileu0022] {n display: none;n }n .inv-demo .btn {n display: inline-flex;n align-items: center;n justify-content: center;n gap: 8px;n padding: 10px 16px;n border-radius: 12px;n border: 1px solid var(u002du002dline);n background: var(u002du002dpill);n cursor: pointer;n font-weight: 500;n text-decoration: none;n }n .inv-demo .btn.primary {n background: #111;n color: #fff;n border-color: #111;n }n .inv-demo .btn[disabled] {n opacity: 0.6;n cursor: not-allowed;n }nn /* Errores por campo */n .inv-demo .error-text {n display: none;n color: var(u002du002derr);n margin-top: 6px;n font-size: 0.9rem;n }n .inv-demo .error-text.show {n display: block;n }n .inv-demo .is-invalid {n border-color: var(u002du002derr) !important;n box-shadow: 0 0 0 2px rgba(176, 0, 32, 0.08) !important;n }n .inv-demo .group-invalid {n border: 1px solid var(u002du002derr-line);n border-radius: 12px;n padding: 10px;n background: var(u002du002derr-bg);n }nn /* IntlTelInput */n .inv-demo .iti {n width: 100%;n }n .inv-demo .iti__flag-container + input {n background: var(u002du002dpill);n border: 1px solid var(u002du002dline);n border-radius: 12px;n padding: 12px 14px 12px 110px;n }nn /* Toast */n .inv-toast {n position: fixed;n left: 50%;n bottom: 16px;n transform: translateX(-50%);n padding: 12px 16px;n border-radius: 12px;n background: #111;n color: #fff;n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);n opacity: 0;n pointer-events: none;n transition: opacity 0.2s ease, transform 0.2s ease;n z-index: 9999;n }n .inv-toast.show {n opacity: 1;n transform: translateX(-50%) translateY(-6px);n }n .inv-toast.success {n background: var(u002du002dok);n }n .inv-toast.info {n background: var(u002du002dinfo);n }n .inv-toast.error {n background: var(u002du002derr);n }nn /* Preview compacta */n .inv-demo .preview {n width: 100%;n max-width: 400px;n aspect-ratio: 16 / 16;n overflow: hidden;n border-radius: 12px;n margin: 8px auto 0;n box-shadow: 0 3px 14px rgba(0, 0, 0, 0.08);n }n .inv-demo .preview img {n width: 100%;n height: 100%;n object-fit: cover;n display: block;n }nu003c/styleu003ennu003cdiv class=u0022inv-demou0022u003en u003cform id=u0022inv-demo-formu0022 novalidateu003en u003c!u002du002d 1) Tipo de boda u002du002du003en u003cfieldset id=u0022fs-tipou0022u003en u003clegendu003e1. De cuál servicio quieres vivir la experienciau003c/legendu003en u003clabelu003en u003cselect id=u0022tipoInvitadosu0022 required aria-describedby=u0022err-tipou0022u003en u003coption value=u0022u0022 selected disabledu003eSelecciona unou003c/optionu003en u003c!u002du002d u003coption value=u0022evento_destinou0022u003en Boda en país/ciudad diferente a la que viven novios e invitadosn u003c/optionu003en u003coption value=u0022evento_mixto_ciudadu0022u003en Boda en la misma ciudad donde viven los novios pero la mayoría den invitados vienen de fueran u003c/optionu003en u003coption value=u0022evento_tradicionalu0022u003en Boda en la misma ciudad donde viven los novios y la mayoría den invitadosn u003c/optionu003e u002du002du003en u003coption value=u0022Boda_Solo_Save_Botonesu0022u003en Confirmación fácil x WhatsApp ( Desde 95usd )n u003c/optionu003en u003coption value=u0022Boda_Tradicionalu0022u003en Invitación con confirmación fácil ( Desde 175 usd )n u003c/optionu003en u003coption value=u0022Boda_Destinou0022u003en Website BODA DESTINO con confirmación fácil ( Desde 399 usd )n u003c/optionu003en u003c/selectu003en u003c/labelu003en u003csmall id=u0022err-tipou0022 class=u0022error-textu0022u003eu003c/smallu003en u003c/fieldsetu003enn u003c!u002du002d 2) Nombres u002du002du003en u003cfieldset id=u0022fs-nombresu0022u003en u003clegendu003e2. Personalizala conu003c/legendu003en u003cdiv class=u0022grid-2u0022u003en u003clabelu003en u003cinputn id=u0022tuNombreu0022n type=u0022textu0022n placeholder=u0022Tu nombreu0022n requiredn aria-describedby=u0022err-nombreu0022n /u003en u003csmall id=u0022err-nombreu0022 class=u0022error-textu0022u003eu003c/smallu003en u003c/labelu003en u003clabelu003en u003cinputn id=u0022nombreAcompu0022n type=u0022textu0022n placeholder=u0022Nombre acompañanteu0022n requiredn aria-describedby=u0022err-nombreau0022n /u003en u003csmall id=u0022err-nombreau0022 class=u0022error-textu0022u003eu003c/smallu003en u003c/labelu003en u003c/divu003en u003c/fieldsetu003enn u003c!u002du002d 3) Imagen o sin foto (MANTENIDO COMENTADO) u002du002du003en u003c!u002du002d u003cfieldset id=u0022fs-fotou0022u003en u003clegendu003e3. Foto de portada personalizadau003c/legendu003en u003cdiv class=u0022file-rowu0022u003en u003cinputn id=u0022portadau0022n type=u0022fileu0022n accept=u0022.jpg,.jpeg,.png,.heic,.heif,.webpu0022n aria-describedby=u0022err-fotou0022n /u003en u003clabel for=u0022portadau0022 class=u0022btnu0022n u003eInsertar una foto o diseño para el ejemplou003c/labeln u003en u003clabel class=u0022chku0022n u003eu003cinput id=u0022sinFotou0022 type=u0022checkboxu0022 /u003en u003cspanu003eSin foto personalizadau003c/spanu003eu003c/labeln u003en u003c/divu003en u003cdiv id=u0022previewu0022 class=u0022previewu0022 hiddenu003eu003c/divu003en u003csmall id=u0022err-fotou0022 class=u0022error-textu0022u003eu003c/smallu003en u003c/fieldsetu003e u002du002du003enn u003c!u002du002d 4) Teléfono u002du002du003en u003cfieldset id=u0022fs-phoneu0022u003en u003clegendu003e3. Ingresa tu número de WhatsAppu003c/legendu003en u003cinputn id=u0022phoneu0022n type=u0022telu0022n placeholder=u0022Tu número de WhatsAppu0022n inputmode=u0022telu0022n requiredn aria-describedby=u0022err-phoneu0022n /u003en u003csmall id=u0022err-phoneu0022 class=u0022error-textu0022u003eu003c/smallu003en u003c/fieldsetu003enn u003c!u002du002d 6) Autorizaciones u002du002du003en u003cfieldset id=u0022fs-termsu0022u003en u003clabel class=u0022chku0022u003en u003cinputn id=u0022aceptoPoliticau0022n type=u0022checkboxu0022n requiredn aria-describedby=u0022err-termsu0022n /u003en u003cspann u003eAcepto lan u003can href=u0022https://invitamosdigital.com/politicas-de-privacidad/u0022n target=u0022_blanku0022n rel=u0022noopeneru0022n u003epolítica de tratamiento de datosu003c/an u003e.u003c/spann u003en u003c/labelu003en u003clabel class=u0022chku0022u003en u003cinputn id=u0022aceptoTerminosu0022n type=u0022checkboxu0022n requiredn aria-describedby=u0022err-termsu0022n /u003en u003cspann u003eAcepto losn u003can href=u0022https://invitamosdigital.com/terminos-servicio/u0022n target=u0022_blanku0022n rel=u0022noopeneru0022n u003etérminos y condicionesu003c/an u003e.u003c/spann u003en u003c/labelu003en u003csmall id=u0022err-termsu0022 class=u0022error-textu0022u003eu003c/smallu003en u003c/fieldsetu003enn u003cbutton id=u0022btnSubmitu0022 class=u0022btn primaryu0022 type=u0022submitu0022u003en Recibir demon u003c/buttonu003en u003cdiv id=u0022statusu0022 class=u0022statusu0022 role=u0022statusu0022 aria-live=u0022politeu0022u003eu003c/divu003en u003cdivn id=u0022inv-toastu0022n class=u0022inv-toastu0022n role=u0022statusu0022n aria-live=u0022politeu0022n u003eu003c/divu003en u003c/formu003enu003c/divu003ennu003c!u002du002d CDN principal con fallback a unpkg u002du002du003enu003cscriptn src=u0022https://cdn.jsdelivr.net/npm/intl-tel-input@23.6.0/build/js/intlTelInput.min.jsu0022n onerror=u0022(function(){var s=document.createElement('script');s.src='https://unpkg.com/intl-tel-input@23.6.0/build/js/intlTelInput.min.js';document.head.appendChild(s);}())u0022nu003eu003c/scriptu003enu003cscriptu003en (function () {n const form = document.getElementById(u0022inv-demo-formu0022);n const btn = document.getElementById(u0022btnSubmitu0022);n const statusBox = document.getElementById(u0022statusu0022);nn /* ===== TEMP: Deshabilitar imagen y forzar sin foto ===== */n const DISABLE_IMAGE_UPLOAD = true; // ← poner en false cuando quieras reactivar imagennn /* ===== Config imagen (front) ===== */n const MAX_FILE_MB = 5; // tope duron const MAX_FILE_BYTES = MAX_FILE_MB * 1024 * 1024;n const STRICT_MAX_BEFORE_COMPRESS = true; // si true, rechaza u003e5MB sin intentar comprimirn const TARGET_MB = 2.5; // objetivo si decides comprimirn const MAX_DIM = 1600; // redimensionadon const JPEG_QUALITY = 0.82;nn /* ===== Imagen: validación + preview + compresión opcional ===== */n // Si está deshabilitado, no buscamos elementos inexistentes.n const inputFile = DISABLE_IMAGE_UPLOAD ? null : document.getElementById(u0022portadau0022);n const sinFotoEl = DISABLE_IMAGE_UPLOAD ? null : document.getElementById(u0022sinFotou0022);n const preview = DISABLE_IMAGE_UPLOAD ? null : document.getElementById(u0022previewu0022);nn const ALLOWED_MIME = new Set([n u0022image/jpegu0022,n u0022image/pngu0022,n u0022image/webpu0022,n u0022image/heicu0022,n u0022image/heifu0022,n u0022image/heic-sequenceu0022,n u0022image/heif-sequenceu0022,n ]);n const ALLOWED_EXT = new Set([u0022jpgu0022, u0022jpegu0022, u0022pngu0022, u0022heicu0022, u0022heifu0022, u0022webpu0022]);nn let fileToSend = null; // archivo efectivo (original o comprimido)nn function isValidImageFile(file) {n if (!file) return false;n const mimeOk = file.type ? ALLOWED_MIME.has(file.type.toLowerCase()) : false;n const ext = (file.name.split(u0022.u0022).pop() || u0022u0022).toLowerCase();n const extOk = ALLOWED_EXT.has(ext);n return mimeOk || extOk;n }n function clearPreview() {n if (!preview) return;n preview.innerHTML = u0022u0022;n preview.hidden = true;n }nn async function shrinkImageIfNeeded(n file,n { maxMB = TARGET_MB, maxWidth = MAX_DIM, quality = JPEG_QUALITY } = {}n ) {n const type = (file.type || u0022u0022).toLowerCase();n if (!/^imageu005c/(jpeg|png|webp)$/.test(type) || file.size u003c= maxMB * 1024 * 1024) {n return file;n }n const img = await new Promise((res, rej) =u003e {n const el = new Image();n el.onload = () =u003e res(el);n el.onerror = rej;n el.src = URL.createObjectURL(file);n });n const scale = Math.min(1, maxWidth / Math.max(img.width, img.height));n const w = Math.max(1, Math.round(img.width * scale));n const h = Math.max(1, Math.round(img.height * scale));n const canvas = document.createElement(u0022canvasu0022);n canvas.width = w;n canvas.height = h;n const ctx = canvas.getContext(u00222du0022);n ctx.drawImage(img, 0, 0, w, h);n const outMime = type.includes(u0022pngu0022) ? u0022image/pngu0022 : u0022image/jpegu0022;n let q = quality;n let blob = await new Promise((r) =u003e canvas.toBlob(r, outMime, q));n while (blob u0026u0026 blob.size u003e maxMB * 1024 * 1024 u0026u0026 q u003e 0.55 u0026u0026 outMime !== u0022image/pngu0022) {n q -= 0.07;n blob = await new Promise((r) =u003e canvas.toBlob(r, outMime, q));n }n if (!blob) return file;n const newName = file.name.replace(/u005c.(png|jpg|jpeg|webp)$/i, outMime === u0022image/pngu0022 ? u0022.pngu0022 : u0022.jpgu0022);n return new File([blob], newName, { type: outMime });n }nn // Solo conectamos listeners si la imagen NO está deshabilitadan if (!DISABLE_IMAGE_UPLOAD) {n inputFile?.addEventListener(u0022changeu0022, async () =u003e {n const fs = document.getElementById(u0022fs-fotou0022);n const f = inputFile.files u0026u0026 inputFile.files[0];n fileToSend = null;nn if (!f) {n clearPreview();n clearFieldError(inputFile, u0022err-fotou0022, fs);n return;n }nn if (!isValidImageFile(f)) {n setFieldError(n inputFile,n u0022Formato no permitido. Sube JPG, JPEG, PNG, HEIC/HEIF o WEBP.u0022,n u0022err-fotou0022,n fsn );n inputFile.value = u0022u0022;n clearPreview();n return;n }nn if (STRICT_MAX_BEFORE_COMPRESS u0026u0026 f.size u003e MAX_FILE_BYTES) {n const mb = (f.size / (1024 * 1024)).toFixed(2);n setFieldError(n inputFile,n `El archivo pesa ${mb} MB. Máximo ${MAX_FILE_MB} MB.`,n u0022err-fotou0022,n fsn );n inputFile.value = u0022u0022;n clearPreview();n return;n }nn let candidate = f;n try {n candidate = await shrinkImageIfNeeded(f);n } catch (_) {n candidate = f;n }nn if (candidate.size u003e MAX_FILE_BYTES) {n const mb = (candidate.size / (1024 * 1024)).toFixed(2);n setFieldError(n inputFile,n `El archivo pesa ${mb} MB. Máximo ${MAX_FILE_MB} MB.`,n u0022err-fotou0022,n fsn );n inputFile.value = u0022u0022;n clearPreview();n return;n }nn fileToSend = candidate;nn const isHeic =n (candidate.type || u0022u0022).toLowerCase().includes(u0022heicu0022) ||n (candidate.type || u0022u0022).toLowerCase().includes(u0022heifu0022);n if (!preview) return;n if (isHeic) {n preview.innerHTML =n 'u003cdiv style=u0022padding:12px;text-align:center;u0022u003eImagen HEIC/HEIF seleccionada (el navegador puede no previsualizarla).u003c/divu003e';n preview.hidden = false;n } else {n const url = URL.createObjectURL(candidate);n preview.innerHTML = 'u003cimg alt=u0022Vista previau0022 src=u0022' + url + 'u0022u003e';n preview.hidden = false;n }n clearFieldError(inputFile, u0022err-fotou0022, fs);n });nn sinFotoEl?.addEventListener(u0022changeu0022, () =u003e {n const fs = document.getElementById(u0022fs-fotou0022);n if (sinFotoEl.checked) {n if (inputFile) {n inputFile.value = u0022u0022;n fileToSend = null;n inputFile.disabled = true;n }n clearPreview();n clearFieldError(inputFile, u0022err-fotou0022, fs);n } else {n if (inputFile) inputFile.disabled = false;n }n });n }nn /* ===== Teléfono: intl-tel-input (bandera USA por defecto) ===== */n const phoneInput = document.getElementById(u0022phoneu0022);n let iti = null;n function initITI() {n if (!window.intlTelInput || !phoneInput) return;n iti = window.intlTelInput(phoneInput, {n initialCountry: u0022usu0022,n separateDialCode: true,n nationalMode: false,n preferredCountries: [u0022usu0022, u0022cou0022, u0022mxu0022, u0022esu0022, u0022aru0022],n autoPlaceholder: u0022politeu0022,n utilsScript:n u0022https://cdn.jsdelivr.net/npm/intl-tel-input@23.6.0/build/js/utils.jsu0022,n });n }n if (document.readyState === u0022completeu0022) initITI();n else window.addEventListener(u0022loadu0022, initITI);nn /* ===== Helpers de UI (status + toast + errores) ===== */n function toast(msg, type = u0022infou0022) {n const el = document.getElementById(u0022inv-toastu0022);n if (!el) return;n el.textContent = msg || u0022u0022;n el.className = u0022inv-toast u0022 + (type || u0022infou0022) + u0022 showu0022;n clearTimeout(el._t);n el._t = setTimeout(() =u003e el.classList.remove(u0022showu0022), 3500);n }n function setBusy(b) {n btn.disabled = b;n btn.textContent = b ? u0022Enviando...u0022 : u0022Enviar demou0022;n btn.setAttribute(u0022aria-busyu0022, b ? u0022trueu0022 : u0022falseu0022);n }n function showStatus(msg, type) {n statusBox.textContent = msg || u0022u0022;n if (type === u0022successu0022) statusBox.style.color = u0022var(u002du002dok)u0022;n else if (type === u0022erroru0022) statusBox.style.color = u0022var(u002du002derr)u0022;n else statusBox.style.color = u0022var(u002du002dinfo)u0022;n toast(msg, type);n }nn function setFieldError(inputEl, message, errId, groupEl) {n if (inputEl) {n inputEl.classList.add(u0022is-invalidu0022);n inputEl.setAttribute(u0022aria-invalidu0022, u0022trueu0022);n }n if (groupEl) {n groupEl.classList.add(u0022group-invalidu0022);n }n const err = document.getElementById(errId);n if (err) {n err.textContent = message;n err.classList.add(u0022showu0022);n }n }n function clearFieldError(inputEl, errId, groupEl) {n if (inputEl) {n inputEl.classList.remove(u0022is-invalidu0022);n inputEl.removeAttribute(u0022aria-invalidu0022);n }n if (groupEl) {n groupEl.classList.remove(u0022group-invalidu0022);n }n const err = document.getElementById(errId);n if (err) {n err.textContent = u0022u0022;n err.classList.remove(u0022showu0022);n }n }nn /* Limpia error al cambiar/escribir */n documentn .getElementById(u0022tipoInvitadosu0022)n ?.addEventListener(u0022changeu0022, () =u003en clearFieldError(n document.getElementById(u0022tipoInvitadosu0022),n u0022err-tipou0022,n document.getElementById(u0022fs-tipou0022)n )n );n documentn .getElementById(u0022tuNombreu0022)n ?.addEventListener(u0022inputu0022, () =u003en clearFieldError(n document.getElementById(u0022tuNombreu0022),n u0022err-nombreu0022,n document.getElementById(u0022fs-nombresu0022)n )n );n documentn .getElementById(u0022nombreAcompu0022)n ?.addEventListener(u0022inputu0022, () =u003en clearFieldError(n document.getElementById(u0022nombreAcompu0022),n u0022err-nombreau0022,n document.getElementById(u0022fs-nombresu0022)n )n );n documentn .getElementById(u0022phoneu0022)n ?.addEventListener(u0022inputu0022, () =u003en clearFieldError(n document.getElementById(u0022phoneu0022),n u0022err-phoneu0022,n document.getElementById(u0022fs-phoneu0022)n )n );n documentn .getElementById(u0022aceptoPoliticau0022)n ?.addEventListener(u0022changeu0022, () =u003en clearFieldError(null, u0022err-termsu0022, document.getElementById(u0022fs-termsu0022))n );n documentn .getElementById(u0022aceptoTerminosu0022)n ?.addEventListener(u0022changeu0022, () =u003en clearFieldError(null, u0022err-termsu0022, document.getElementById(u0022fs-termsu0022))n );nn /* ===== Utils ===== */nfunction splitPhone(itiInstance, raw) {n const stripPlus = (s) =u003e (s || u0022u0022).toString().replace(/^u005c+/, u0022u0022);nn if (itiInstance) {n const e164 = itiInstance.getNumber() || u0022u0022; // p.ej. +573001112233n const cd = itiInstance.getSelectedCountryData() || {};n const dial = stripPlus(cd.dialCode); // p.ej. u002257u0022n const digits = e164.replace(/u005cD/g, u0022u0022); // p.ej. u0022573001112233u0022n const cel = dial u0026u0026 digits.startsWith(dial)n ? digits.slice(dial.length)n : digits; // p.ej. u00223001112233u0022nn return {n indicativo: dial || null, // u002257u0022 (sin +)n celular: cel || null,n valid: itiInstance.isValidNumber(),n };n } else {n // Fallback cuando no hay iti: inferir indicativo + númeron const cleaned = (raw || u0022u0022).replace(/u005cs+/g, u0022u0022);n const m = cleaned.match(/^u005c+?(u005cd{1,4})(u005cd{6,15})$/); // (indicativo)(celular)n if (m) {n return {n indicativo: stripPlus(m[1]), // u003cu003cu003c sin u0022+u0022n celular: m[2],n valid: true,n };n }n const d = cleaned.replace(/u005cD/g, u0022u0022);n return {n indicativo: null,n celular: d || null,n valid: d.length u003e= 7,n };n }n}nn /* Limitar teléfono a MÁX 11 dígitos (sin indicativo) */n (function enforcePhoneMax() {n const fsPhone = document.getElementById(u0022fs-phoneu0022);n function capPhone() {n let digits = phoneInput.value.replace(/u005cD/g, u0022u0022);n if (digits.length u003e 11) {n digits = digits.slice(0, 11);n setFieldError(phoneInput, u0022Máximo 11 dígitosu0022, u0022err-phoneu0022, fsPhone);n } else {n clearFieldError(phoneInput, u0022err-phoneu0022, fsPhone);n }n phoneInput.value = digits;n }n phoneInput.addEventListener(u0022inputu0022, capPhone);n phoneInput.addEventListener(u0022bluru0022, capPhone);n phoneInput.addEventListener(u0022pasteu0022, () =u003en requestAnimationFrame(capPhone)n );n })();nn /* ===== Submit + envío a API ===== */n form.addEventListener(u0022submitu0022, async function (e) {n e.preventDefault();n showStatus(u0022u0022, u0022infou0022);nn const fsTipo = document.getElementById(u0022fs-tipou0022);n const fsNombres = document.getElementById(u0022fs-nombresu0022);n const fsFoto = document.getElementById(u0022fs-fotou0022); // puede ser null (fieldset comentado)n const fsPhone = document.getElementById(u0022fs-phoneu0022);n const fsTerms = document.getElementById(u0022fs-termsu0022);nn const tipoEvento = document.getElementById(u0022tipoInvitadosu0022).value || u0022u0022;n const nombre = (document.getElementById(u0022tuNombreu0022).value || u0022u0022).trim();n const nombreAcomp = (document.getElementById(u0022nombreAcompu0022).value || u0022u0022).trim();n const aceptaPolitica = document.getElementById(u0022aceptoPoliticau0022).checked;n const aceptaTerminos = document.getElementById(u0022aceptoTerminosu0022).checked;nn // Limpia estados de error previosn clearFieldError(document.getElementById(u0022tipoInvitadosu0022), u0022err-tipou0022, fsTipo);n clearFieldError(document.getElementById(u0022tuNombreu0022), u0022err-nombreu0022, fsNombres);n clearFieldError(document.getElementById(u0022nombreAcompu0022), u0022err-nombreau0022, fsNombres);n clearFieldError(inputFile, u0022err-fotou0022, fsFoto);n clearFieldError(document.getElementById(u0022phoneu0022), u0022err-phoneu0022, fsPhone);n clearFieldError(null, u0022err-termsu0022, fsTerms);nn // Validaciones por campon let firstFocus = null;nn if (!tipoEvento) {n setFieldError(n document.getElementById(u0022tipoInvitadosu0022),n u0022Selecciona el tipo de bodau0022,n u0022err-tipou0022,n fsTipon );n firstFocus = firstFocus || document.getElementById(u0022tipoInvitadosu0022);n }n if (!nombre) {n setFieldError(document.getElementById(u0022tuNombreu0022), u0022Escribe tu nombreu0022, u0022err-nombreu0022, fsNombres);n firstFocus = firstFocus || document.getElementById(u0022tuNombreu0022);n }n if (!nombreAcomp) {n setFieldError(n document.getElementById(u0022nombreAcompu0022),n u0022Escribe el nombre de tu acompañanteu0022,n u0022err-nombreau0022,n fsNombresn );n firstFocus = firstFocus || document.getElementById(u0022nombreAcompu0022);n }nn // TEMP: al estar deshabilitada la imagen, forzamos sin foto.n const isSinFoto = DISABLE_IMAGE_UPLOAD ? true : !!sinFotoEl?.checked;n const hasFile = !!(inputFile u0026u0026 inputFile.files u0026u0026 inputFile.files[0]);nn // Solo validamos imagen si NO es u0022sin fotou0022 y la imagen está activan if (!isSinFoto u0026u0026 !DISABLE_IMAGE_UPLOAD) {n if (!hasFile) {n setFieldError(inputFile, u0022Sube una imagen o marca “Sin foto”u0022, u0022err-fotou0022, fsFoto);n firstFocus = firstFocus || inputFile;n }n if (hasFile u0026u0026 !fileToSend) {n setFieldError(inputFile, u0022Revisa el formato y peso de la imagen.u0022, u0022err-fotou0022, fsFoto);n firstFocus = firstFocus || inputFile;n }n if (fileToSend u0026u0026 fileToSend.size u003e MAX_FILE_MB * 1024 * 1024) {n setFieldError(inputFile, `El archivo supera ${MAX_FILE_MB} MB.`, u0022err-fotou0022, fsFoto);n firstFocus = firstFocus || inputFile;n }n }nn const rawPhone = (phoneInput.value || u0022u0022).trim();n const phoneParts = splitPhone(iti, rawPhone);n const digitsLen = (phoneParts.celular || u0022u0022).replace(/u005cD/g, u0022u0022).length;n if (!phoneParts.valid || digitsLen u003c 7 || digitsLen u003e 11) {n setFieldError(n phoneInput,n u0022Ingresa un número válido (7–11 dígitos)u0022,n u0022err-phoneu0022,n fsPhonen );n firstFocus = firstFocus || phoneInput;n }nn if (!aceptaPolitica || !aceptaTerminos) {n setFieldError(n null,n u0022Debes aceptar la política y los términosu0022,n u0022err-termsu0022,n fsTermsn );n firstFocus = firstFocus || document.getElementById(u0022aceptoPoliticau0022);n }nn if (firstFocus) {n if (firstFocus.scrollIntoView)n firstFocus.scrollIntoView({ behavior: u0022smoothu0022, block: u0022centeru0022 });n if (firstFocus.focus) setTimeout(() =u003e firstFocus.focus(), 250);n return; // no envía si hay erroresn }nn // ===== Construir y enviar a /api/demopersonalizable =====n //console.log(u0022Enviando demo personalizada...u0022);n //const API_URL = u0022http://localhost:4535/api/demopersonalizableu0022; // devn const API_URL = u0022https://teinvitamos.co/api/demopersonalizableu0022; // prodnn // JSON que el back normaliza (normalizeLeadFromMultipartOrJson)n const lead = {n nombre: nombre || null,n nombreAcomp: nombreAcomp || null,nn celular: phoneParts.celular || null,n indicativo: phoneParts.indicativo || null,nn email: (document.getElementById(u0022emailu0022)?.value || u0022u0022).trim() || null,n cedula: (document.getElementById(u0022cedulau0022)?.value || u0022u0022).trim() || null,n cantidadInvitados:n (document.getElementById(u0022cantidadInvitadosu0022)?.value || u0022u0022).trim() || null,n fechaEvento:n (document.getElementById(u0022fechaEventou0022)?.value || u0022u0022).trim() || null,nn tipoEvento: tipoEvento || null,n demoTipo: tipoEvento || null, // u0022evento_destinou0022 | u0022evento_mixto_ciudadu0022 | u0022evento_tradicionalu0022nn aceptoPolitica: !!aceptaPolitica,n aceptoTerminos: !!aceptaTerminos,n };nn // 1) preparar sinFoto para el back (FORZADO mientras está deshabilitado)n const sinFotoValue = isSinFoto ? u00221u0022 : u00220u0022;n lead.sinFoto = isSinFoto;nn // 2) crea el FormData y agrega camposn const fd = new FormData();n fd.append(u0022sinFotou0022, sinFotoValue);n fd.append(u0022leadu0022, JSON.stringify(lead));nn // 3) solo adjunta archivo si NO es sin foto (y si imagen está activa)n if (!isSinFoto u0026u0026 !DISABLE_IMAGE_UPLOAD u0026u0026 hasFile u0026u0026 fileToSend) {n fd.append(u0022portadau0022, fileToSend, fileToSend.name);n }nn // DEBUGn // console.log(u0022POST →u0022, API_URL);n // console.log(u0022lead →u0022, lead);n if (fileToSend)n console.log(u0022portada →u0022, {n name: fileToSend.name,n type: fileToSend.type,n size: fileToSend.size,n });nn setBusy(true);n try {n const res = await fetch(API_URL, {n method: u0022POSTu0022,n headers: { Accept: u0022application/jsonu0022 }, // NO Content-Typen body: fd,n });nn const raw = await res.text();n let payload = null;n try {n payload = JSON.parse(raw);n } catch (_) {}n console.log(u0022Respuesta API ←u0022, res.status, payload || raw);nn if (!res.ok) {n showStatus(n u0022Ups, Algo pasó con tu número y no se pudo procesar la solicitud. Escríbenos por favor a contactoyasesoria@invitamosdigital.com y te ayudaremosu0022,n u0022erroru0022n );n console.error(u0022API error:u0022, res.status, raw);n return;n }nn const msg =n payload u0026u0026 typeof payload.mensaje === u0022stringu0022n ? payload.mensaje.toLowerCase()n : u0022u0022;nn if (msg.includes(u0022celular ya registradou0022)) {n showStatus(n u0022Gracias por tu solicitud. Para acceder a demos adicionales: • Solicítalos en el Whatsapp que te llegó el primer demo o • Agenda una asesoría personalizada dando click en el botón agendar llamadau0022,n u0022infou0022n );n return;n }nn // Caso de prueba actual (subida correcta) o flujo estándarn showStatus(n u0022¡Envío exitoso! En unos segundos te llegará el mensaje por WhatsApp. u0022,n u0022successu0022n );n form.reset();n clearPreview();n fileToSend = null;n if (iti) iti.setCountry(u0022usu0022);n } catch (err) {n console.error(err);n showStatus(n u0022Algo falló. Escríbenos a contactoyasesoria@invitamosdigital.comu0022,n u0022erroru0022n );n } finally {n setBusy(false);n }n });n })();nu003c/scriptu003en