// Invite / lead-capture page: /join/[?v=] // Email first (code sign-in creates the account), wallet later inside the // member area. The angle only changes the hook copy; the sponsor cookie was // set by the server when this page was served. (function () { const $ = id => document.getElementById(id); const ANGLES = { instant: { eyebrow: 'Same-transaction payouts', h: 'Paid before the page reloads.', lead: 'What if your commission landed before the thank-you page finished loading? On InstantAdPay that is not a metaphor. A smart contract on Polygon splits every ad package the moment it sells.' }, adspend: { eyebrow: 'For marketers who buy traffic', h: 'You were buying ads anyway.', lead: 'Every ad dollar you ever spent went one direction: out. Here the ad spend in your line pays you, in the same transaction, on a public ledger. Seven formats, dwell-timed views, packages from $5.' }, free: { eyebrow: 'Costs nothing to try', h: 'Watch first. Spend never.', lead: 'Join free, view a few ads, earn credits, and run your first campaign for zero dollars. Upgrade only if you want more reach.' }, ledger: { eyebrow: 'No back office', h: 'No back office. No payday.', lead: 'Your last program paid you on the 15th, if it paid you. Here every payout is a public transaction on Polygon you can read yourself, and nothing is ever held.' }, two: { eyebrow: 'The referral side, exactly as coded', h: 'Two buyers open level two.', lead: 'Every direct buyer pays you 50 percent from their first package. Two qualifying buyers open level two, five open level three. Written as constants in a verified contract.' } }; const v = new URLSearchParams(location.search).get('v'); const a = v && ANGLES[v]; if (a) { $('jnEyebrow').textContent = a.eyebrow; $('jnHead').innerHTML = a.h; $('jnLead').textContent = a.lead; } async function api(path, body) { const r = await (await fetch(path, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body || {}) })).json(); if (r.error) throw new Error(r.error); return r; } const err = m => { const e = $('jnErr'); e.textContent = m || ''; e.hidden = !m; }; function busy(btn, fn) { return async () => { if (btn.disabled) return; btn.disabled = true; err(''); try { await fn(); } catch (e) { err(e.message || 'Something went wrong.'); } finally { btn.disabled = false; } }; } const send = busy($('jnSend'), async () => { const r = await api('/api/auth/email/start', { email: $('jnEmail').value }); $('jnCodeRow').hidden = false; $('jnVerify').hidden = false; $('jnSend').hidden = true; $('jnResend').hidden = false; if (r.devCode) $('jnCode').value = r.devCode; IAP.status(r.sent ? 'Code sent. Check your inbox (and spam, the first time).' : 'Dev mode: code filled in.', 'ok'); $('jnCode').focus(); }); $('jnSend').addEventListener('click', send); $('jnResend').addEventListener('click', busy($('jnResend'), async () => { const r = await api('/api/auth/email/start', { email: $('jnEmail').value }); if (r.devCode) $('jnCode').value = r.devCode; IAP.status('Fresh code sent.', 'ok'); })); $('jnVerify').addEventListener('click', busy($('jnVerify'), async () => { await api('/api/auth/email/verify', { email: $('jnEmail').value, code: $('jnCode').value, newsletter: !!$('jnNews').checked, followups: !!$('jnNews').checked }); IAP.status('You are in. Taking you to your dashboard…', 'ok'); location.href = '/my?welcome=1'; // dashboard runs the username step + welcome tour on arrival })); $('jnEmail').addEventListener('keydown', e => { if (e.key === 'Enter') ($('jnVerify').hidden ? $('jnSend') : $('jnVerify')).click(); }); $('jnCode').addEventListener('keydown', e => { if (e.key === 'Enter') $('jnVerify').click(); }); // sponsor line fetch('/api/sponsor').then(r => r.json()).then(sp => { if (sp && sp.invited && sp.name) { $('jnSponName').textContent = sp.name; if (sp.avatarUrl) { $('jnSponImg').src = sp.avatarUrl; $('jnSponImg').hidden = false; } $('jnSpon').hidden = false; } }).catch(() => {}); // package ladder (dollar constants + live POL quote) const NAMES = { 1: 'Micro', 2: 'Activation', 3: 'Builder', 4: 'Growth', 5: 'Leader' }; fetch('/api/catalog').then(r => r.json()).then(c => { const wrap = $('jnLadder'); if (!wrap || !c.products) return; wrap.innerHTML = c.products.filter(p => p.active !== false).map(p => '
' + (NAMES[p.id] || 'Package ' + p.id) + '
' + IAP.fmtUsd(p.priceCents) + '
' + Number(p.creditAmount).toLocaleString() + ' credits
' + (p.costWei ? '
' + IAP.fmtPol(p.costWei) + ' POL now
' : '') + '
').join(''); }).catch(() => {}); fetch('/api/stats').then(r => r.json()).then(s => { if (s && s.onchainMembers) $('jnStats').textContent = s.onchainMembers.toLocaleString() + (s.onchainMembers === 1 ? ' member' : ' members') + ' on-chain so far.'; }).catch(() => {}); })();