/* ============================================================ Miss XV VIP — Order Flow (order-wizard.jsx) À la carte en USD · 5 pasos · preview + video demos en vivo Solo capa visual/UX. Sin backend real. ============================================================ */ const { useState, useMemo, useEffect, useRef } = React; /* ---------- helpers de cliente (sin backend) ---------- */ // Copia texto al portapapeles con fallback a un input temporal + execCommand. async function copyText(text) { try { if (navigator.clipboard && navigator.clipboard.writeText) { await navigator.clipboard.writeText(text); return true; } } catch (e) { /* cae al fallback */ } try { const ta = document.createElement('textarea'); ta.value = text; ta.setAttribute('readonly', ''); ta.style.position = 'fixed'; ta.style.top = '-9999px'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.focus(); ta.select(); const ok = document.execCommand('copy'); document.body.removeChild(ta); return ok; } catch (e) { return false; } } // Lee un File como data URL (para guardarlo en el borrador, sin servidor). function fileToDataURL(file, cb) { const r = new FileReader(); r.onload = (e) => cb(e.target.result); r.readAsDataURL(file); } // Botón "Copiar" con confirmación visual breve. function CopyChip({ text, label = 'Copiar' }) { const [done, setDone] = useState(false); const onCopy = async (e) => { e.preventDefault(); e.stopPropagation(); const ok = await copyText(String(text)); if (ok) { setDone(true); setTimeout(() => setDone(false), 1500); } }; return ( ); } /* ---------- icons ---------- */ const P = { check: 'M20 6L9 17l-5-5', chevright: 'M9 18l6-6-6-6', chevleft: 'M15 18l-6-6 6-6', x: 'M18 6L6 18M6 6l12 12', plus: 'M12 5v14M5 12h14', eye: 'M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8zM12 15a3 3 0 100-6 3 3 0 000 6z', play: 'M6 4l14 8-14 8V4z', pause: 'M6 4h4v16H6zM14 4h4v16h-4z', sparkle: 'M12 2l1.8 5.5L19.5 9l-5.7 1.5L12 16l-1.8-5.5L4.5 9l5.7-1.5z', star: 'M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.27 5.82 22 7 14.14l-5-4.87 6.91-1.01z', qr: 'M3 3h7v7H3zM14 3h7v7h-7zM3 14h7v7H3zM14 14h2v2h-2zM18 14h3v3h-3zM14 18h2v3h-2zM18 19h3v2h-3z', image: 'M19 3H5a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V5a2 2 0 00-2-2zM8.5 10a1.5 1.5 0 100-3 1.5 1.5 0 000 3zM21 15l-5-5L5 21', film: 'M3 3h18v18H3zM7 3v18M17 3v18M3 8h4M3 16h4M17 8h4M17 16h4M3 12h18', users: 'M16 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2M8.5 11a4 4 0 100-8 4 4 0 000 8zM23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75', user: 'M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2M12 11a4 4 0 100-8 4 4 0 000 8z', calendar: 'M19 4H5a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2zM16 2v4M8 2v4M3 10h18', clock: 'M12 22a10 10 0 100-20 10 10 0 000 20zM12 6v6l4 2', mappin: 'M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0zM12 13a3 3 0 100-6 3 3 0 000 6z', palette: 'M12 22a10 10 0 110-20 10 10 0 0110 8 4 4 0 01-4 4h-2a2 2 0 00-1 4 2 2 0 01-3 2zM6.5 12a1.5 1.5 0 100-3 1.5 1.5 0 000 3zM10.5 8a1.5 1.5 0 100-3 1.5 1.5 0 000 3zM15.5 8a1.5 1.5 0 100-3 1.5 1.5 0 000 3z', heart: 'M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z', edit: 'M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7M18.5 2.5a2.121 2.121 0 113 3L12 15l-4 1 1-4 9.5-9.5z', seat: 'M3 18v-6a3 3 0 013-3h12a3 3 0 013 3v6M3 18h18M5 18v2M19 18v2M6 9V7a3 3 0 013-3h6a3 3 0 013 3v2', lock: 'M19 11H5a2 2 0 00-2 2v7a2 2 0 002 2h14a2 2 0 002-2v-7a2 2 0 00-2-2zM7 11V7a5 5 0 0110 0v4', shield: 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z', gift: 'M20 12v10H4V12M2 7h20v5H2zM12 22V7M12 7H7.5a2.5 2.5 0 010-5C11 2 12 7 12 7zM12 7h4.5a2.5 2.5 0 000-5C13 2 12 7 12 7z', zap: 'M13 2L3 14h9l-1 8 10-12h-9l1-8z', crown: 'M3 18l2-11 5 6 2-8 2 8 5-6 2 11z', message: 'M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z', globe: 'M12 22a10 10 0 100-20 10 10 0 000 20zM2 12h20M12 2a15 15 0 010 20 15 15 0 010-20z', shirt: 'M16 3l4 3-3 3-1-1v11H8V8L7 9 4 6l4-3 2 2h4z', ticket: 'M3 8a2 2 0 012-2h14a2 2 0 012 2v2a2 2 0 000 4v2a2 2 0 01-2 2H5a2 2 0 01-2-2v-2a2 2 0 000-4zM12 6v2M12 11v2M12 16v2', music: 'M9 18V5l12-2v13M9 18a3 3 0 11-6 0 3 3 0 016 0zM21 16a3 3 0 11-6 0 3 3 0 016 0z', mail: 'M4 4h16a2 2 0 012 2v12a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2zM22 6l-10 7L2 6', info: 'M12 22a10 10 0 100-20 10 10 0 000 20zM12 8h.01M11 12h1v4h1' }; function Ic({ n, s = 16, style, cls }) { return ( ); } function GoogleG({ s = 18 }) { return ( ); } /* ---------- catálogo real (USD) ---------- */ const SERVICES = [ { id: 'invitacion', base: true, name: 'Invitación Digital VIP Original', short: 'Tu invitación base, personalizada', price: 100, icon: 'sparkle', tint: '#f5c945', badge: 'Invitación', demoUrl: 'https://www.missxvvip.com/inv/xv-maria-fernanda-valdes', desc: 'La invitación digital animada y personalizada a tu medida, siempre incluida en tu orden.' }, { id: 'savedate', name: 'Anuncia tu Fecha', short: 'Save the Date', price: 150, icon: 'calendar', tint: '#b347ff', badge: 'Save the Date', desc: 'Video animado para anunciar tu fecha y crear expectativa entre tus invitados.' }, { id: 'historia', name: 'Cuenta tu Historia', short: 'Video Cronológico', price: 300, popular: true, icon: 'film', tint: '#fb923c', badge: 'Tu Historia', desc: 'Video cronológico que narra tu historia con fotos y momentos clave.' }, { id: 'qrvip', name: 'Vive tu Fiesta', short: 'QR-VIP · álbum y photo wall', price: 75, icon: 'qr', tint: '#22d34a', badge: 'QR-VIP', desc: 'Álbum colaborativo y photo wall en vivo: tus invitados suben fotos con un QR.' }, { id: 'seating', name: 'Organiza tus Mesas', short: 'SP-VIP · mapa de mesas', price: 75, icon: 'seat', tint: '#3b8bd6', badge: 'Seating', desc: 'Seating planner visual para acomodar tus mesas e invitados sin estrés.' }, { id: 'slideshow', name: 'VIP Slideshow', short: '3 videos en 1', price: 100, was: 300, icon: 'image', tint: '#ec4899', badge: 'Slideshow', desc: 'Tres videos integrados en una sola pieza espectacular para tu pantalla.' }]; /* cargo por invitación bilingüe (EN/ES) */ const BILINGUAL_PRICE = 25; const bilingualFee = (lang) => lang === 'bi' ? BILINGUAL_PRICE : 0; const THEMES = [ { id: 'esmeralda', name: 'Esmeralda Real', mood: 'Botánico · señorial', bg: ['#16341f', '#0a1d11'], text: '#FFF8E6', accent: '#E8C76B', dots: ['#1f5a33', '#E8C76B', '#FFF8E6'] }, { id: 'rosa', name: 'Rosa Cuarzo', mood: 'Romántico · suave', bg: ['#3a1f2e', '#1c0e16'], text: '#FFEFF4', accent: '#F2A7BB', dots: ['#7a3450', '#F2A7BB', '#FFEFF4'] }, { id: 'lavanda', name: 'Lavanda VIP', mood: 'Moderno · etéreo', bg: ['#241640', '#120a26'], text: '#F3ECFF', accent: '#d4a3ff', dots: ['#5a2e9e', '#d4a3ff', '#F3ECFF'] }, { id: 'dorado', name: 'Dorado Clásico', mood: 'Atemporal · lujo', bg: ['#14161f', '#08080d'], text: '#FFF8E6', accent: '#f5c945', dots: ['#2a2a3a', '#f5c945', '#FFF8E6'] }]; const STEPS = ['Tus servicios', 'La festejada', 'Secciones', 'Temática', 'Resumen', 'Pago']; /* secciones de la invitación VIP real (VIPINV_SECTIONS del portal INV) — core = siempre activa; req = servicio del que dependen */ const SECTIONS = [ { id: 'video_intro', name: 'Video de intro / apertura', desc: 'Pantalla animada de bienvenida', icon: 'play' }, { id: 'hero', name: 'Portada', desc: 'Nombre y fecha principal', icon: 'crown' }, { id: 'countdown', name: 'Cuenta regresiva', desc: 'Días, horas y minutos al gran día', icon: 'clock' }, { id: 'parents', name: 'Padres / Padrinos', desc: 'Con la bendición de…', icon: 'heart' }, { id: 'ceremony', name: 'Ceremonia', desc: 'Misa o acto religioso', icon: 'sparkle' }, { id: 'reception', name: 'Recepción', desc: 'Dirección, hora y mapa del salón', icon: 'mappin' }, { id: 'itinerary', name: 'Itinerario', desc: 'Programa del evento', icon: 'calendar' }, { id: 'dress_code', name: 'Vestimenta', desc: 'Código de vestimenta', icon: 'shirt' }, { id: 'registry', name: 'Mesa de Regalos', desc: 'Links a tu registro o datos', icon: 'gift' }, { id: 'corte', name: 'Corte de Honor', desc: 'Chambelanes y damas de honor', icon: 'users' }, { id: 'gallery', name: 'Galería', desc: 'Hasta 6 fotos en tu invitación', icon: 'image' }, { id: 'music', name: 'Música de fondo', desc: 'Activa una pista al abrir', icon: 'music' }, { id: 'qrvip', name: 'Álbum de Fotos QR', desc: 'Muro de fotos colaborativo de invitados', icon: 'qr' }, { id: 'rsvp', name: 'RSVP', desc: 'Confirmación de asistencia', icon: 'mail' }, { id: 'guestbook', name: 'Libro de Visitas', desc: 'Mensajes y firmas de invitados', icon: 'message' }, { id: 'thanks', name: 'Agradecimiento', desc: 'Mensaje de cierre', icon: 'sparkle' }, { id: 'map', name: 'Mapa / Ubicación', desc: 'Cómo llegar al evento', icon: 'globe' }]; const REQ_LABEL = { slideshow: 'VIP Slideshow', qrvip: 'QR-VIP', savedate: 'Save the Date' }; /* las secciones son contenido libre — el cliente las enciende/apaga, no dependen de servicios */ function secAvailable() {return true;} /* paquetes de inicio rápido — precios fijos de negocio (ids no-base) */ const PKGS = [ { id: 'esencial', name: 'Esencial', icon: 'sparkle', price: 100, tagline: 'Tu invitación digital, lista para brillar.', items: [] }, { id: 'premium', name: 'Premium', icon: 'star', popular: true, price: 200, tagline: 'Invitación + QR + Seating + VIP Slideshow.', items: ['qrvip', 'seating', 'slideshow'] }, { id: 'lujo', name: 'Lujo VIP', icon: 'crown', price: 500, tagline: 'Todo incluido: video crono, save the date y slideshow.', items: ['qrvip', 'seating', 'savedate', 'historia', 'slideshow'] }]; function pkgActive(services, pkg) { if (services.size !== pkg.items.length) return false; return pkg.items.every((id) => services.has(id)); } function findPkg(services) {return PKGS.find((p) => pkgActive(services, p)) || null;} function pkgListValue(pkg) {return SERVICES.filter((s) => s.base || pkg.items.includes(s.id)).reduce((a, s) => a + s.price, 0);} /* CARRILES SEPARADOS: paquete = precio fijo sin promos | à la carte = lista + promos por monto */ function orderState(services) { const pkg = findPkg(services); if (pkg) return { mode: 'pkg', pkg, total: pkg.price, gross: pkg.price, discount: 0, freeIds: new Set(), freeQS: false, freeSlide: false }; return { mode: 'alc', pkg: null, ...calcTotals(services) }; } const USD = (n) => '$' + n.toLocaleString('en-US'); const USD2 = (n) => '$' + n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); /* ── COMISIÓN TARJETA (Stripe) ────────────────────────────────── Ajusta estos dos valores a la tasa real de tu cuenta Stripe. El recargo SOLO aplica a pagos con tarjeta; el cliente lo absorbe. */ const CARD_FEE_PCT = 0.029; // 2.9 % const CARD_FEE_FIXED = 0.30; // $0.30 USD por transacción /* Stripe activo: cuando es false, no se muestra el sello "Recomendado" en tarjeta */ const STRIPE_ACTIVE = false; /* grossing-up: lo que cobramos para recibir `total` neto tras la comisión */ function cardCharge(total) { return Math.round((total + CARD_FEE_FIXED) / (1 - CARD_FEE_PCT) * 100) / 100; } const MESES = ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre']; const PAY = { zelle: { handle: '(818) 674-3792', titular: 'Manuel Acevedo' }, venmo: { handle: '@missxvvip' } }; /* número de WhatsApp del negocio (formato wa.me, sin + ni espacios). Edítalo aquí. */ const WHATSAPP_NUMBER = '18183106910'; function waLink(msg) {return `https://wa.me/${WHATSAPP_NUMBER}?text=${encodeURIComponent(msg)}`;} function fmtDate(d) { if (!d) return null; const [y, m, day] = d.split('-').map(Number); if (!y || !m || !day) return null; return `${String(day).padStart(2, '0')} de ${MESES[m - 1]} de ${y}`; } const capMes = (m) => m.charAt(0).toUpperCase() + m.slice(1); /* etiqueta de fecha flexible: exacta · mes/año · por confirmar */ function eventDateLabel(data) { const mode = data.dateMode || 'exact'; if (mode === 'tbd') return 'Fecha por confirmar'; if (mode === 'monthyear') { if (!data.dateMY) return null; const [y, m] = data.dateMY.split('-').map(Number); if (!y || !m) return null; return `${capMes(MESES[m - 1])} ${y}`; } return fmtDate(data.date); } /* ¿la fecha quedó pendiente de afinar? (tbd o mes/año o vacía) */ function dateIsPending(data) { const mode = data.dateMode || 'exact'; if (mode === 'tbd') return true; if (mode === 'monthyear') return !data.dateMY; return !data.date; } /* folio único de orden para reconciliar pagos (Zelle/Venmo) */ function genFolio() {return 'MXV-' + (1000 + Math.floor(Math.random() * 9000));} function countdown(d, t) { if (!d) return null; const diff = new Date(`${d}T${t || '20:00'}:00`) - new Date(); if (isNaN(diff) || diff <= 0) return null; return { days: Math.floor(diff / 86400000), hrs: Math.floor(diff % 86400000 / 3600000), min: Math.floor(diff % 3600000 / 60000) }; } /* promo-aware totals */ function calcTotals(services) { const chosen = SERVICES.filter((s) => s.base || services.has(s.id)); const gross = chosen.reduce((a, s) => a + s.price, 0); const freeQS = gross >= 400,freeSlide = gross >= 700; const freeIds = new Set(); let discount = 0; chosen.forEach((s) => { if (freeQS && (s.id === 'qrvip' || s.id === 'seating')) {discount += s.price;freeIds.add(s.id);} if (freeSlide && s.id === 'slideshow') {discount += s.price;freeIds.add(s.id);} }); return { gross, discount, total: gross - discount, freeIds, freeQS, freeSlide }; } /* ============================================================ PANEL DERECHO — invitación en vivo ============================================================ */ function Preview({ data, totals, step }) { const th = THEMES.find((t) => t.id === data.theme) || THEMES[0]; const cd = (data.dateMode || 'exact') === 'exact' ? countdown(data.date, data.time) : null; const dateStr = eventDateLabel(data); const badges = SERVICES.filter((s) => !s.base && data.services.has(s.id)).map((s) => s.badge); const sec = data.sections; const pills = ['Eligiendo tus servicios', 'Capturando los datos', 'Eligiendo secciones', 'Aplicando la temática', 'Revisando tu orden', 'Lista para publicar']; const nameStyle = data.style === 'moderno' ? { fontFamily: "'Poppins', sans-serif", fontStyle: 'normal', fontWeight: 800, letterSpacing: '-0.02em', textTransform: 'uppercase', fontSize: 33 } : {}; return (
{sec.hero &&
Mis XV Años
} {sec.hero &&
{data.honoree || 'Tu Festejada'}
} {sec.hero &&
} {data.welcome &&
{data.welcome}
} {sec.hero &&
{dateStr || 'Fecha por definir'}
} {sec.countdown && cd &&
{[['días', cd.days], ['hrs', cd.hrs], ['min', cd.min]].map(([l, v]) =>
{String(v).padStart(2, '0')}
{l}
)}
} {sec.reception && (data.venue || data.city) &&
{data.venue &&
{data.venue}
} {data.city &&
{data.city}
} {data.recepTime &&
Recepción · {data.recepTime}
}
} {sec.parents && (data.mom || data.dad || data.padrinos) &&
Con la bendición de
{data.mom &&
{data.mom}
} {data.mom && data.dad &&
&
} {data.dad &&
{data.dad}
} {data.padrinos &&
{data.padrinos}
}
} {sec.corte && data.corteNames &&
Corte de Honor
{data.corteNames}
} {sec.dress_code && data.dressCode &&
{data.dressCode}
} {badges.length > 0 &&
{badges.map((b) => {b})}
} {sec.thanks &&
Miss XV VIP
}
{pills[step]}
); } /* ============================================================ PANEL DERECHO — video demos (paso 1) ============================================================ */ function VideoShowcase({ data, set, toggleSvc, focus, setFocus, totals, activePkg }) { const [playing, setPlaying] = useState(false); const svc = SERVICES.find((s) => s.id === focus) || SERVICES[0]; const isFree = totals.freeIds.has(svc.id); const on = svc.base || data.services.has(svc.id); const inPkg = !!activePkg && on && !svc.base; const toggle = () => {if (!svc.base) toggleSvc(svc.id);}; React.useEffect(() => {setPlaying(false);}, [focus]); return (
{svc.demoUrl ? 'En vivo ↑' : `Demo · ${svc.badge}`}
{inPkg ? Incluido : isFree ? GRATIS : <>{svc.was && {USD(svc.was)}}{USD(svc.price)}}
{svc.demoUrl ? 'Invitación real · en vivo' : playing ? '0:04 / 0:18' : '0:18'}
{svc.name}
{svc.desc}
{inPkg ? Incluido en paquete : isFree ? GRATIS · promo : USD(svc.price)}
{svc.demoUrl && Ver invitación real}
{SERVICES.map((s) => { const added = s.base || data.services.has(s.id); return ( ); })}
); } /* ============================================================ helpers de form ============================================================ */ function Field({ label, opt, hint, children, full }) { return (
{children} {hint && {hint}}
); } function AccountGate({ data, set }) { const emailOk = /.+@.+\..+/.test(data.cEmail); const passOk = data.cPass.length >= 8; if (data.auth) { const initial = (data.cName || data.cEmail || 'U').trim().charAt(0).toUpperCase(); return (
{initial}
{data.cName || 'Tu cuenta Miss XV VIP'}
{data.cEmail}
Progreso guardado
); } return (
Crea tu cuenta para guardar tu progreso
Continúa cuando quieras y, con la misma cuenta, accede a tu RSVP, invitados y álbum QR.
o
set({ cEmail: e.target.value })} />
set({ cPass: e.target.value })} />
¿Ya tienes cuenta? set({ auth: true, authMethod: 'email', cEmail: data.cEmail || 'cliente@correo.com' })}>Inicia sesión
); } /* ============================================================ PASO 1 — cuenta + servicios à la carte + promos ============================================================ */ function StepServices({ data, set, totals, toggleSvc, focus, setFocus }) { const toggle = (s) => {if (!s.base) toggleSvc(s.id);}; const toGo400 = Math.max(0, 400 - totals.gross); const toGo700 = Math.max(0, 700 - totals.gross); const activePkg = findPkg(data.services); return (

Bienvenida, Miss XV VIP

Aquí empieza tu historia. Elige y personaliza tu invitación paso a paso, a tu manera, con una vista previa en vivo mientras decides. Al confirmar tu orden, nuestro equipo produce la versión final —fondos, estilos y animación de intro— y te la entrega en 1 a 3 días. Nosotros nos encargamos del resto. ♡

Empieza con un paquete — o personaliza abajo

{PKGS.map((p) => { const active = pkgActive(data.services, p); const t = p.price; const list = pkgListValue(p); const save = list - t; return ( ); })}
{activePkg ?
Paquete {activePkg.name} seleccionado · {activePkg.items.length + 1} {activePkg.items.length + 1 === 1 ? 'servicio' : 'servicios'} por {USD(activePkg.price)} USD. Agrega o quita abajo para personalizarlo.
:
{totals.freeQS ? <>¡Desbloqueado! QR-VIP y Seating GRATIS en tu orden. : <>Agrega {USD(toGo400)} más y llévate QR-VIP + Seating gratis ($400+).}
{!totals.freeQS &&
}
{totals.freeSlide ? <>¡Desbloqueado! VIP Slideshow GRATIS en tu orden. : <>Llega a $700 y el VIP Slideshow es gratis — te faltan {USD(toGo700)}.}
{!totals.freeSlide &&
}
}

O personaliza servicio por servicio — toca para ver el demo, + para agregar

{SERVICES.map((s) => { const on = s.base || data.services.has(s.id); const free = totals.freeIds.has(s.id); return (
setFocus(s.id)} onClick={() => setFocus(s.id)}>
{s.name}{s.popular && Más popular}Demo
{s.short} · {s.base ? 'siempre incluida' : s.desc}
{activePkg && on ? Incluido : <> {s.was && !free && {USD(s.was)}} {free ? GRATIS : USD(s.price)} }
); })}
); } function StepHonoree({ data, set }) { const mode = data.dateMode || 'exact'; return (

Datos del evento

Cuéntanos lo esencial para comenzar a crear tu invitación.

set({ honoree: e.target.value })} />
{[['exact', 'Fecha exacta'], ['monthyear', 'Mes y año'], ['tbd', 'Por confirmar']].map(([m, lbl]) => )}
{mode === 'exact' &&
set({ date: e.target.value })} /> set({ time: e.target.value })} aria-label="Hora" />
} {mode === 'monthyear' && set({ dateMY: e.target.value })} /> } {mode === 'tbd' &&
Tu invitación dirá “Fecha por confirmar”. Podrás fijar el día después desde tu panel.
}
set({ venue: e.target.value })} /> set({ city: e.target.value })} />

Papás y padrinos · opcional

set({ mom: e.target.value })} /> set({ dad: e.target.value })} /> set({ padrinos: e.target.value })} />
); } /* secciones cuyo contenido se arma después en el panel (no se captura en la compra) */ const SEC_PANEL_NOTE = { itinerary: 'Arma el programa del día (horarios y momentos) en tu panel.', gallery: 'Sube tus fotos (hasta 6) desde tu panel después de comprar.', music: 'Elige la pista de la biblioteca o sube la tuya en tu panel.', qrvip: 'El álbum colaborativo se activa y configura en tu panel.', video_intro: 'La animación de apertura es preparada por nuestro equipo según el estilo de tu evento.' }; function SecInlineFields({ id, data, set }) { if (id === 'reception') return (
set({ recepAddr: e.target.value })} /> set({ recepTime: e.target.value })} /> set({ recepMaps: e.target.value })} />
); if (id === 'registry') return (