// nexa-sections-2.jsx — Sistemas, Proceso, CTA, Footer // ---------- Sistemas ---------- const Sistemas = () => { const [active, setActive] = React.useState(0); const items = [ { tag: "WhatsApp", t: "WhatsApp centralizado", d: "Todas las consultas en un solo lugar. Nada se pierde entre teléfonos.", mock: , }, { tag: "Pipeline", t: "Pipeline industrial", d: "Qué trabajos están cotizados, aprobados o pendientes. En una pantalla.", mock: , }, { tag: "Panel", t: "Panel comercial", d: "Consultas, cierres y facturación en tiempo real.", mock: , }, { tag: "Clientes", t: "Clientes y presupuestos", d: "Historial de cada cliente, cada trabajo, cada presupuesto.", mock: , }, ]; return (
04 · El sistema

Así se ve funcionando.

{/* List */}
{items.map((it, i) => ( ))}
{/* Mock viewer */}
{items.map((it, i) => (
{it.mock}
))}
); }; // --- Animated counter hook --- const useCounter = (target, { duration = 1500, decimals = 0, suffix = '', prefix = '' } = {}) => { const [val, setVal] = React.useState(0); const ref = React.useRef(null); React.useEffect(() => { const el = ref.current; if (!el) return; let started = false; const io = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting && !started) { started = true; const start = performance.now(); const tick = (now) => { const t = Math.min(1, (now - start) / duration); const eased = 1 - Math.pow(1 - t, 3); setVal(target * eased); if (t < 1) requestAnimationFrame(tick); else setVal(target); }; requestAnimationFrame(tick); io.unobserve(el); } }); }, { threshold: 0.4 }); io.observe(el); return () => io.disconnect(); }, [target, duration]); const formatted = decimals === 0 ? Math.floor(val).toLocaleString('es-AR') : val.toFixed(decimals); return { ref, text: prefix + formatted + suffix }; }; // --- MockChat: animated typing conversation --- const MockChat = () => { const [step, setStep] = React.useState(0); const visibleRef = React.useRef(null); const [active, setActive] = React.useState(false); React.useEffect(() => { const el = visibleRef.current; if (!el) return; const io = new IntersectionObserver((es) => { es.forEach(e => { if (e.isIntersecting) setActive(true); }); }, { threshold: 0.3 }); io.observe(el); return () => io.disconnect(); }, []); React.useEffect(() => { if (!active) return; // pasos 0..6 normales, 7 = pausa de 3.5s antes de reset const seq = [800, 1400, 1100, 1600, 1300, 1500, 3500]; let i = 0; let id; const tick = () => { setStep(s => (s + 1) % 8); i++; id = setTimeout(tick, seq[i % seq.length]); }; id = setTimeout(tick, 600); return () => clearTimeout(id); }, [active]); const showMsg1 = step >= 2 && step <= 7; const showMsg2 = step >= 4 && step <= 7; const showMsg3 = step >= 5 && step <= 7; const showMsg4 = step >= 6 && step <= 7; const typingThem = step === 1; const typingMe = step === 3; return (
N
Nexa Bot
En línea
{showMsg1 && Hola, quería un presupuesto para una estructura metálica.} {typingMe && } {showMsg2 && ¡Hola! Perfecto. ¿Podés enviarnos medidas o foto de referencia?} {showMsg3 && Sí, te paso ahora.} {showMsg4 && Genial. Registramos tu consulta y un asesor te envía el presupuesto.} {typingThem && }
IA respondiendo · derivá si necesita
); }; const Msg = ({ side, children }) => (
{children}
); const TypingDots = ({ side }) => (
{[0, 1, 2].map(i => ( ))}
); // --- MockPipeline: lead moves from Nuevos → Contactados → Cerrados --- const MockPipeline = () => { const [phase, setPhase] = React.useState(0); // 0=Nuevos, 1=Contactados, 2=Cerrados const [counts, setCounts] = React.useState([12, 8, 5]); const [activeRef, setActiveRef] = React.useState(false); const rootRef = React.useRef(null); React.useEffect(() => { const el = rootRef.current; if (!el) return; const io = new IntersectionObserver(es => es.forEach(e => { if (e.isIntersecting) setActiveRef(true); }), { threshold: 0.3 }); io.observe(el); return () => io.disconnect(); }, []); React.useEffect(() => { if (!activeRef) return; let i = 0; let id; const tick = () => { setPhase(p => { const next = (p + 1) % 3; if (next === 1) setCounts(c => [c[0] - 1, c[1] + 1, c[2]]); else if (next === 2) setCounts(c => [c[0], c[1] - 1, c[2] + 1]); else setCounts([12, 8, 5]); return next; }); i++; // después de completar el ciclo (3 fases) deja 3s antes de seguir const delay = (i % 3 === 0) ? 5200 : 2200; id = setTimeout(tick, delay); }; id = setTimeout(tick, 2200); return () => clearTimeout(id); }, [activeRef]); const cols = [ { t: "Consulta", c: "#7AA0FF" }, { t: "Cotizado", c: "#F5C26B" }, { t: "Aprobado", c: "#5BD9A6" }, ]; return (
{cols.map((col, i) => (
{col.t} {counts[i]}
{Array.from({ length: 3 }).map((_, j) => { const isActive = phase === i && j === 0; return (
); })}
))}
); }; // --- MockDashboard: counters + drawing chart + bars --- const MockDashboard = () => { const sales = useCounter(2890000, { duration: 2000, prefix: '$ ' }); const orders = useCounter(10, { duration: 1400 }); const contacts = useCounter(78, { duration: 1600 }); const closed = useCounter(10, { duration: 1500 }); const today = useCounter(327, { duration: 1700 }); return (
{/* Hero stat: ventas hoy big */}
Facturado hoy
{sales.text}
{orders.text} ventas ↑ +24% vs ayer
EN VIVO
{/* Secondary stats row */}
Contactados
{contacts.text}
+18 hoy
Cerrados
{closed.text}
+9% sem.
Msj contestados
{today.text}
último: 2m
{/* Chart with growing line + bars */}
Ventas / día últimos 30d
{[ { x: 10, h: 30 }, { x: 30, h: 38 }, { x: 50, h: 28 }, { x: 70, h: 50 }, { x: 90, h: 42 }, { x: 110, h: 60 }, { x: 130, h: 52 }, { x: 150, h: 70 }, { x: 170, h: 64 }, { x: 190, h: 78 }, { x: 210, h: 70 }, { x: 230, h: 86 }, { x: 250, h: 80 }, { x: 270, h: 92 }, { x: 290, h: 100 }, ].map((b, i) => ( ))}
); }; // --- MockCRM: animated rows with live updates --- const MockCRM = () => { const [tick, setTick] = React.useState(0); const ref = React.useRef(null); React.useEffect(() => { const el = ref.current; if (!el) return; let id; const io = new IntersectionObserver(es => es.forEach(e => { if (e.isIntersecting) { let count = 0; const next = () => { setTick(t => t + 1); count++; const delay = (count % 5 === 0) ? 5800 : 2400; id = setTimeout(next, delay); }; id = setTimeout(next, 2400); } else if (id) { clearTimeout(id); id = null; } }), { threshold: 0.3 }); io.observe(el); return () => { if (id) clearTimeout(id); io.disconnect(); }; }, []); const rowsData = [ { name: "Estructura Galpón", baseAmount: 8400, status: ["En curso", "Activo", "Activo"], c: "#5BD9A6" }, { name: "Corte Láser CNC", baseAmount: 1850, status: ["Activo", "Activo", "Activo"], c: "#5BD9A6" }, { name: "Reja Industrial 12m", baseAmount: 3200, status: ["Activo", "En curso", "Activo"], c: "#F5C26B" }, { name: "Plegado Chapa 4mm", baseAmount: 920, status: ["Cotizado", "En curso", "Activo"], c: "#7AA0FF" }, { name: "Soldadura Pampa SA", baseAmount: 14500, status: ["Activo", "Activo", "Activo"], c: "#5BD9A6" }, ]; const fmt = (n) => n === 0 ? '—' : `$ ${n.toLocaleString('es-AR')}`; const statusColor = (s) => s === 'Activo' ? '#5BD9A6' : s === 'En curso' ? '#F5C26B' : '#7AA0FF'; const statusBg = (s) => s === 'Activo' ? 'rgba(91,217,166,0.12)' : s === 'En curso' ? 'rgba(245,194,107,0.12)' : 'rgba(122,160,255,0.12)'; const statusBorder = (s) => s === 'Activo' ? 'rgba(91,217,166,0.25)' : s === 'En curso' ? 'rgba(245,194,107,0.25)' : 'rgba(122,160,255,0.25)'; // Live "new lead" indicator that pulses each tick const liveIdx = tick % rowsData.length; return (
nexa.crm / presupuestos EN VIVO
{rowsData.map((r, i) => { const status = r.status[tick % r.status.length]; const amount = r.baseAmount + (i + tick) * 37 * (i % 2 === 0 ? 1 : -1) + tick * 12; const isLive = i === liveIdx; return ( ); })}
Presupuesto Estado Monto Últ. acción
{r.name.split(' ').map(s => s[0]).join('').slice(0, 2)} {r.name} {isLive && } {status} {fmt(Math.max(0, amount))} {isLive ? 'ahora' : `${(i + 1) * 4 + (tick % 5)}m`}
); }; // ---------- Proceso ---------- const Proceso = () => { const steps = [ { n: "01", t: "Diagnóstico", d: "Detectamos dónde se pierden oportunidades." }, { n: "02", t: "Captura y Organización", d: "Ordenamos consultas y presupuestos." }, { n: "03", t: "Seguimiento Inteligente", d: "Ningún presupuesto queda olvidado." }, { n: "04", t: "Conversión", d: "Más presupuestos convertidos en trabajos." }, { n: "05", t: "Control y Mejora", d: "Métricas claras para mejorar decisiones." }, ]; const [reached, setReached] = React.useState(-1); const rootRef = React.useRef(null); React.useEffect(() => { const el = rootRef.current; if (!el) return; const io = new IntersectionObserver(es => es.forEach(e => { if (e.isIntersecting) { steps.forEach((_, i) => setTimeout(() => setReached(r => Math.max(r, i)), 400 + i * 700)); io.unobserve(el); } }), { threshold: 0.25 }); io.observe(el); return () => io.disconnect(); }, []); return (
02 · Método

Método FCI™

Flujo Comercial Inteligente. 5 fases.

{steps.map((s, i) => { const on = reached >= i; return (
{s.n}

{s.t}

{s.d}

); })}
); }; // ---------- CTA ---------- const CTA = () => (

Cada presupuesto sin seguimiento
es una oportunidad perdida.

Analizamos tu operación comercial en 30 minutos. Cupos limitados por mes.

); // ---------- Footer ---------- const Footer = () => (

Ayudamos a escalar negocios.

© 2026 Nexa Business Growth · Argentina · LATAM Hecho con ☕ y código.
); const FooterCol = ({ t, links }) => ( ); const FabWsp = () => { const onClick = (e) => { e.preventDefault(); window.open(WSP_URL, '_blank', 'noopener'); }; return ( ); }; Object.assign(window, { Sistemas, Proceso, CTA, Footer, FabWsp });