// My account: email-first join/login, wallet link at purchase time, // free payout activation, invite link, on-chain activity. (async function () { await IAP.renderNav('my'); const $ = IAP.$; 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; } async function render() { const me = await IAP.refreshNavWallet(); const signedIn = me && me.signedIn; $('authArea').hidden = !!signedIn; $('memberArea').hidden = !signedIn; if (!signedIn) return; const who = []; if (me.email) who.push(me.email); if (me.address) who.push('wallet ' + me.address.slice(0, 8) + '…' + me.address.slice(-6) + ''); else who.push('no wallet linked yet'); if (me.memberId) who.push('on-chain member #' + me.memberId + '' + (me.onchainSponsorId ? ', sponsored by #' + me.onchainSponsorId : '')); else if (me.sponsorId) who.push('invited by member #' + me.sponsorId); $('posLine').innerHTML = who.join('
'); $('creditLine').textContent = (me.credits || 0).toLocaleString(); $('linkCard').hidden = !!me.address; $('activateCard').hidden = !(me.address && !me.memberId); $('activityArea').hidden = !me.memberId; $('campaignCard').hidden = !me.memberId; if (me.memberId) loadCampaigns(); if (me.memberId) { const bc = me.buyerCount || 0; $('qualLine').innerHTML = '' + bc + ' qualifying buyer(s) referred
' + (bc >= 5 ? 'Level 3 unlocked: full three-level earnings' : bc >= 2 ? 'Level 2 unlocked · ' + (5 - bc) + ' more for level 3' : (2 - bc) + ' more buyer(s) of $20+ unlock level 2'); $('inviteLine').textContent = location.origin + '/join/' + me.memberId; $('copyInvite').hidden = false; loadActivity(); } else { $('qualLine').textContent = 'Level 1 pays the moment you are on-chain. Referrals who buy packages of $20 or more unlock levels 2 and 3.'; $('inviteLine').textContent = me.address ? 'Activate payouts above and your invite link appears here.' : 'Link a wallet and switch on payouts to get your invite link.'; $('copyInvite').hidden = true; } } async function loadActivity() { try { const c = await IAP.getConfig(); const a = await (await fetch('/api/my/activity')).json(); const fill = (id, evs, empty) => { const el = $(id); el.innerHTML = ''; if (!evs || !evs.length) { el.innerHTML = '
' + empty + '
'; return; } for (const ev of evs) el.appendChild(IAP.feedRow(ev, c)); }; fill('earnFeed', a.earnings, 'No payouts yet. They appear here the moment one lands.'); fill('refFeed', a.referrals, 'No referral activity yet. Share your invite link.'); fill('buyFeed', a.purchases, 'No purchases from your wallet yet.'); } catch (e) {} } async function loadCampaigns() { try { const r = await (await fetch('/api/my/campaigns')).json(); if (r.error) return; $('rateLine').textContent = 'Available to spend: ' + r.availableCredits.toLocaleString() + ' credits · rates: banner ' + r.rates.bannerCreditsPerBatch + 'cr/' + r.rates.bannerBatch + ' views, text ' + r.rates.textCreditsPerBatch + 'cr/' + r.rates.textBatch + ' views, login ' + r.rates.loginCreditsPerDay + 'cr/day'; const el = $('campList'); el.innerHTML = ''; if (!r.campaigns.length) { el.innerHTML = '

No campaigns yet. Launch your first below.

'; return; } const tbl = document.createElement('div'); tbl.className = 'tablewrap'; tbl.innerHTML = '' + '' + r.campaigns.map(c => '' + '' + '' + '' + '').join('') + '
NameTypeViewsClicksSpentBudgetStatus
' + c.name + '' + c.type + '' + c.imps.toLocaleString() + '' + c.clicks + '' + c.spent + '' + c.budget + '' + (c.status === 'out' ? 'budget spent' : c.status) + '' + (c.status === 'active' ? '' : c.status === 'paused' ? '' : '') + '
'; el.appendChild(tbl); el.querySelectorAll('button[data-camp]').forEach(b => b.addEventListener('click', async () => { try { await api('/api/my/campaigns/' + b.dataset.camp + '/' + b.dataset.act); await loadCampaigns(); } catch (e) { IAP.status(e.message, 'bad'); } })); } catch (e) {} } $('cType').addEventListener('change', () => { const t = $('cType').value; $('cImageRow').hidden = t === 'text'; $('cTitleRow').hidden = t !== 'text'; $('cBodyRow').hidden = t !== 'text'; }); $('createCampBtn').addEventListener('click', busy2($('createCampBtn'), async () => { await api('/api/my/campaigns', { type: $('cType').value, name: $('cName').value, targetUrl: $('cTarget').value, imageUrl: $('cImage').value, title: $('cTitle').value, body: $('cBody').value, budget: Number($('cBudget').value) }); IAP.status('Campaign is live. It starts serving right away.', 'ok'); $('cName').value = ''; $('cBudget').value = ''; await loadCampaigns(); })); // defers the busy() lookup to click time (busy is declared below) function busy2(btn, fn) { return (...a) => busy(btn, fn)(...a); } const busy = (btn, fn) => async () => { try { btn.disabled = true; await fn(); } catch (e) { IAP.status((e && e.message) || String(e), 'bad'); } finally { btn.disabled = false; } }; // passwordless (feature-flagged on config.emailAuth): code replaces passwords (async () => { const cfg = await IAP.getConfig(); if (!cfg.emailAuth) return; $('passCards').hidden = true; $('magicCard').hidden = false; const start = busy($('mcSendBtn'), async () => { const r = await api('/api/auth/email/start', { email: $('mcEmail').value }); $('mcCodeRow').hidden = false; $('mcVerifyBtn').hidden = false; $('mcSendBtn').hidden = true; $('mcResend').hidden = false; if (r.devCode) { $('mcCode').value = r.devCode; IAP.status('Dev mode: code filled in for you.', 'ok'); } else IAP.status('Code sent. Check your inbox (and spam, the first time).', 'ok'); $('mcCode').focus(); }); $('mcSendBtn').addEventListener('click', start); $('mcResend').addEventListener('click', busy($('mcResend'), async () => { const r = await api('/api/auth/email/start', { email: $('mcEmail').value }); if (r.devCode) $('mcCode').value = r.devCode; IAP.status('Fresh code sent.', 'ok'); })); $('mcVerifyBtn').addEventListener('click', busy($('mcVerifyBtn'), async () => { await api('/api/auth/email/verify', { email: $('mcEmail').value, code: $('mcCode').value }); IAP.status('You are in.', 'ok'); await render(); })); })(); $('signupBtn').addEventListener('click', busy($('signupBtn'), async () => { await api('/api/signup', { email: $('suEmail').value, password: $('suPass').value }); IAP.status('Welcome aboard. You are in.', 'ok'); await render(); })); $('loginBtn').addEventListener('click', busy($('loginBtn'), async () => { await api('/api/login', { email: $('liEmail').value, password: $('liPass').value }); IAP.status('Logged in.', 'ok'); await render(); })); $('walletSigninLink').addEventListener('click', async e => { e.preventDefault(); try { IAP.status('Check your wallet for the free sign-in signature…'); await IAPWallet.signIn(); IAP.status('Signed in with your wallet.', 'ok'); await render(); } catch (err) { IAP.status((err && err.message) || String(err), 'bad'); } }); $('linkBtn').addEventListener('click', busy($('linkBtn'), async () => { IAP.status('Check your wallet for the free link signature…'); await IAPWallet.signIn(); // server binds the wallet to the signed-in email account IAP.status('Wallet linked. Earnings pay there from now on.', 'ok'); await render(); })); $('activateBtn').addEventListener('click', busy($('activateBtn'), async () => { const me = await (await fetch('/api/me')).json(); IAP.status('Confirm the free activation in your wallet…'); const r = await IAPWallet.activate(me.sponsorId || 0); if (r.receipt.status !== '0x1') throw new Error('Transaction reverted. Check the explorer.'); IAP.status('Payouts are on. Your invite link is live.', 'ok'); await render(); })); $('copyInvite').addEventListener('click', async () => { try { await navigator.clipboard.writeText($('inviteLine').textContent); IAP.status('Link copied.', 'ok'); } catch (e) { IAP.status('Copy failed. Select and copy the link text.', 'bad'); } }); $('logoutLink').addEventListener('click', async e => { e.preventDefault(); await fetch('/api/auth/logout', { method: 'POST' }); IAP.status('Logged out.', 'ok'); await render(); }); render(); })();