// First-engagement email capture popup // Triggers after first click/scroll/keydown anywhere on the page. // Stores submission + dismiss state in localStorage so it never re-prompts. function NewsletterPopup(){ const STORAGE_KEY = 'thraxel-newsletter-popup-v1'; const [open, setOpen] = React.useState(false); const [form, setForm] = React.useState({ name:'', email:'', phone:'', opt:true }); const [submitted, setSubmitted] = React.useState(false); const [error, setError] = React.useState(''); React.useEffect(()=>{ let prior; try { prior = localStorage.getItem(STORAGE_KEY); } catch(e){} if (prior) return; // already shown / dismissed / submitted let triggered = false; const trigger = () => { if (triggered) return; triggered = true; // Small delay so the click doesn't feel hijacked setTimeout(()=> setOpen(true), 450); cleanup(); }; const onClick = (e) => { // Don't fire on the popup itself or on links inside the nav opening within first frame if (e.target.closest && e.target.closest('.nl-popup')) return; trigger(); }; const onScroll = () => { if (window.scrollY > 200) trigger(); }; const onKey = () => trigger(); window.addEventListener('click', onClick, { passive:true }); window.addEventListener('scroll', onScroll, { passive:true }); window.addEventListener('keydown', onKey, { passive:true }); function cleanup(){ window.removeEventListener('click', onClick); window.removeEventListener('scroll', onScroll); window.removeEventListener('keydown', onKey); } return cleanup; },[]); const close = () => { try { localStorage.setItem(STORAGE_KEY, JSON.stringify({ dismissed:true, t:Date.now() })); } catch(e){} setOpen(false); }; const submit = (e) => { e.preventDefault(); setError(''); if (!form.name.trim()) return setError('Please enter your name.'); if (!/^\S+@\S+\.\S+$/.test(form.email)) return setError('Please enter a valid email.'); if (!form.phone.trim() || form.phone.replace(/\D/g,'').length < 7) return setError('Please enter a valid phone number.'); try { localStorage.setItem(STORAGE_KEY, JSON.stringify({ submitted:true, t:Date.now(), email:form.email })); } catch(e){} setSubmitted(true); setTimeout(()=> setOpen(false), 2200); }; if (!open) return null; return (
{/* Close */} {!submitted ? ( <>
THRAXEL INSIDER

Get on the list.

Drop your details below for early access to seasonal install windows, member-only discounts, and the occasional behind-the-scenes from the field. No spam — that's a promise.

setForm(f=>({...f, name:v}))} autoFocus/> setForm(f=>({...f, email:v}))}/> setForm(f=>({...f, phone:v}))} placeholder="(555) 555-5555"/> {error &&
{error}
}
) : (

You're in.

Welcome to the inside. We'll be in touch.

)}
); } function NLInput({ label, value, onChange, type='text', placeholder, autoFocus }){ return ( ); } Object.assign(window, { NewsletterPopup });