/* eslint-disable */ /* global React */ const { useState, useEffect, useRef, useCallback } = React; const WA = "https://wa.me/541126285230"; const waLink = (t) => `${WA}?text=${encodeURIComponent(t)}`; /* ---------- hooks ---------- */ function useScrolled(threshold){ const [s, setS] = useState(false); useEffect(() => { const on = () => setS(window.scrollY > (threshold||20)); on(); window.addEventListener('scroll', on, { passive:true }); return () => window.removeEventListener('scroll', on); }, []); return s; } function useInView(opts){ const ref = useRef(null); const [seen, setSeen] = useState(false); useEffect(() => { const el = ref.current; if(!el) return; if(!('IntersectionObserver' in window)){ setSeen(true); return; } const io = new IntersectionObserver(([e]) => { if(e.isIntersecting){ setSeen(true); io.disconnect(); } }, { threshold: 0.18, rootMargin: '0px 0px -8% 0px', ...(opts||{}) }); io.observe(el); // Fallback: never leave content hidden if IO doesn't fire (bg tab / print / capture). // Only force-reveal elements that are already at/above the viewport, or when the page // isn't visible (print/capture/background) — so below-the-fold sections keep waiting // for the observer and animate when the user actually scrolls to them. const fb = setTimeout(() => { const r = el.getBoundingClientRect(); if(r.top < window.innerHeight || document.visibilityState === 'hidden'){ setSeen(true); } }, 1400); return () => { io.disconnect(); clearTimeout(fb); }; }, []); return [ref, seen]; } function Reveal({ children, className, delay, as, ...rest }){ const [ref, seen] = useInView(); const Tag = as || 'div'; const style = delay ? { transitionDelay: delay+'ms', ...(rest.style||{}) } : rest.style; return {children}; } function useCycle(list, ms){ const [i, setI] = useState(0); useEffect(() => { const t = setInterval(() => setI(p => (p+1)%list.length), ms); return () => clearInterval(t); }, []); return i; } function CountUp({ to, suffix, prefix, dur }){ const [ref, seen] = useInView(); const [v, setV] = useState(0); useEffect(() => { if(!seen) return; let raf, start; const D = dur||1500; const tick = (t) => { if(!start) start = t; const p = Math.min((t-start)/D, 1); setV(Math.floor((1-Math.pow(1-p,3))*to)); if(p<1) raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [seen, to]); return {prefix||''}{v.toLocaleString('es-AR')}{suffix||''}; } /* ---------- icons ---------- */ const IgIcon = () => (); const InIcon = () => (); const WaIcon = () => (); const Arrow = () => (); const Check = () => (); /* nav links for inner pages — anchors resolve back to the home page */ const SUB_LINKS = [ ['Servicios', '/#servicios'], ['Auditoría', '/auditoria'], ['Asesoría', '/asesoria'], ['Sobre mí', '/#sobremi'], ['Proceso', '/#proceso'], ['Recursos', '/recursos'], ['FAQ', '/#faq'], ]; /* ---------- Nav ---------- */ const NAV_LINKS = [ ['Servicios', '#servicios'], ['Auditoría', '/auditoria'], ['Asesoría', '/asesoria'], ['Sobre mí', '#sobremi'], ['Proceso', '#proceso'], ['Recursos', '/recursos'], ['FAQ', '#faq'], ]; function Nav({ links }){ const scrolled = useScrolled(); const [open, setOpen] = React.useState(false); const items = links || NAV_LINKS; React.useEffect(() => { document.body.style.overflow = open ? 'hidden' : ''; return () => { document.body.style.overflow = ''; }; }, [open]); return ( <>
setOpen(false)}>
{items.map(([l,h]) => setOpen(false)}>{l.toLowerCase()})} Hablemos
); } /* ---------- Footer ---------- */ function Footer(){ return ( ); } /* ---------- SectionHead ---------- */ function SectionHead({ idx, title, lead, id }){ return (
{idx}

{title}

{lead ?

{lead}

: null}
); } Object.assign(window, { useScrolled, useInView, Reveal, useCycle, CountUp, IgIcon, InIcon, WaIcon, Arrow, Check, Nav, Footer, SectionHead, WA, waLink, NAV_LINKS, SUB_LINKS, });