Files
instantadpay/public/assets/ledger.js
T
martbost bee13ba4b8 Ad engine v1: banner/text/login campaigns against on-chain credits
Spec 8b types 1-3. Spend accrues per campaign in batches; burns queue for
the engine signer (admin runs consume() on-chain, /api/admin/burns). Rates
are volume config (adrates.json), rehearsal placeholders until Marty sets
the real card. Public slots serve on the ledger page; campaign manager in
the members area.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-04 13:04:47 -05:00

32 lines
1.2 KiB
JavaScript

// Live ledger: recent history + SSE stream of new chain events.
(async function () {
await IAP.renderNav('ledger');
const c = await IAP.getConfig();
IAP.$('contractLink').href = c.explorer + '/address/' + c.contract;
const feed = IAP.$('feed');
const { events } = await (await fetch('/api/feed?n=150')).json();
feed.innerHTML = '';
if (!events.length) feed.innerHTML = '<div class="row muted">No activity yet. The first purchase will appear here the moment it lands.</div>';
for (const ev of events) feed.appendChild(IAP.feedRow(ev, c));
try {
const stats = await (await fetch('/api/stats')).json();
IAP.$('statLine').textContent = stats.onchainMembers + ' on-chain member(s)';
} catch (e) {}
IAP.adSlot('banner', 'adSlotBanner');
IAP.adSlot('text', 'adSlotText');
const es = new EventSource('/api/feed/live');
es.onopen = () => { const b = IAP.$('liveBadge'); b.textContent = '● live'; };
es.onerror = () => { const b = IAP.$('liveBadge'); b.textContent = 'reconnecting…'; };
es.onmessage = m => {
try {
const ev = JSON.parse(m.data);
feed.prepend(IAP.feedRow(ev, c));
while (feed.children.length > 200) feed.removeChild(feed.lastChild);
} catch (e) {}
};
})();