// Shared page runtime: site config, nav, formatting. Zero dependencies. window.IAP = (function () { let config = null; const $ = id => document.getElementById(id); async function getConfig() { if (!config) config = await (await fetch('/api/config')).json(); return config; } function fmtPol(wei) { const s = BigInt(wei).toString().padStart(19, '0'); const whole = s.slice(0, -18) || '0'; const frac = s.slice(-18, -12).replace(/0+$/, ''); return whole + (frac ? '.' + frac : ''); } const fmtUsd = cents => '$' + (cents / 100).toFixed(2); function status(msg, cls) { let el = $('status'); if (!el) { el = document.createElement('div'); el.id = 'status'; document.body.appendChild(el); } el.textContent = msg; el.className = cls || ''; el.hidden = false; clearTimeout(status._t); if (cls === 'ok') status._t = setTimeout(() => { el.hidden = true; }, 6000); } async function renderNav(active) { const c = await getConfig(); const nav = document.createElement('nav'); nav.innerHTML = '
' + '' + '' + 'How it works' + 'Live ledger' + 'My account' + 'โ€ฆ
'; document.body.prepend(nav); if (c.rehearsal) { const b = document.createElement('div'); b.className = 'rehearsal'; b.innerHTML = 'Testnet rehearsal โ€” running on ' + c.chainName + '. Purchases use valueless test POL while we prove every payout in public.'; document.body.prepend(b); } const a = nav.querySelector('[data-p="' + active + '"]'); if (a) a.style.color = 'var(--ink)'; refreshNavWallet(); } async function refreshNavWallet() { try { const me = await (await fetch('/api/me')).json(); const el = $('navWallet'); if (!el) return; if (me.signedIn) { el.innerHTML = (me.memberId ? 'member #' + me.memberId + ' ' : '') + '' + me.address.slice(0, 6) + 'โ€ฆ' + me.address.slice(-4) + ''; } else { el.innerHTML = 'Sign in'; } return me; } catch (e) { return null; } } function describeEvent(ev, c) { const pol = w => fmtPol(w) + ' POL'; switch (ev.type) { case 'Purchase': return '๐Ÿงพ member #' + ev.buyerId + ' bought package #' + ev.productId + ' (' + fmtUsd(ev.priceCents) + ') for ' + pol(ev.paidWei) + ' โ†’ +' + ev.creditAmount.toLocaleString() + ' credits'; case 'TierPaid': return '๐Ÿ’ธ level ' + ev.tier + ' payout โ†’ member #' + ev.recipientId + ': ' + pol(ev.amountWei) + (ev.hops ? ' (passed up ' + ev.hops + ')' : ''); case 'PassedUp': return 'โ†ท level ' + ev.tier + ' passed over #' + ev.skippedId + ' (' + ev.reason + ')'; case 'AdminPaid': return '๐Ÿ› platform fee settled: ' + pol(ev.amountWei); case 'BuyerCounted': return 'โญ member #' + ev.sponsorId + ' now has ' + ev.newCount + ' qualifying buyer(s)'; case 'MemberActivated': return '๐Ÿ‘ค member #' + ev.id + ' activated a payout wallet'; case 'AwardPaid': return '๐ŸŽ award: ' + pol(ev.amountWei) + ' โ†’ member #' + ev.toId; case 'CreditsConsumed': return '๐Ÿ“ฃ member #' + ev.memberId + ' ran ads: โˆ’' + ev.amount.toLocaleString() + ' credits'; case 'PriceCached': return '๐Ÿ”ฎ oracle price refreshed'; case 'FallbackPriceUsed': return '๐Ÿ”ฎ cached price bridged an oracle gap'; default: return 'ยท ' + ev.type; } } function feedRow(ev, c) { const div = document.createElement('div'); div.className = 'row t-' + ev.type; div.innerHTML = '' + describeEvent(ev, c) + '' + 'verify โ†—'; return div; } return { getConfig, fmtPol, fmtUsd, status, renderNav, refreshNavWallet, describeEvent, feedRow, $ }; })();