From a4c7028c0ee536a6db68e0b59b73857a98f775de Mon Sep 17 00:00:00 2001 From: martbost Date: Sat, 5 Sep 2026 06:07:33 -0500 Subject: [PATCH] Buy packages pane inside the member back office Members buy directly from the dashboard: live-priced tiles in a dedicated menu section, wallet flow with buy-time sponsor resolution, dashboard refresh on settle. No more round-trip to the homepage. Assets v=20260905e. Co-Authored-By: Claude Fable 5 --- public/assets/my.js | 41 +++++++++++++++++++++++++++++++++++++++-- public/contract.html | 8 ++++---- public/index.html | 10 +++++----- public/ledger.html | 8 ++++---- public/my.html | 20 +++++++++++++++----- 5 files changed, 67 insertions(+), 20 deletions(-) diff --git a/public/assets/my.js b/public/assets/my.js index b7ed121..148e57c 100644 --- a/public/assets/my.js +++ b/public/assets/my.js @@ -68,8 +68,8 @@ } // ── back-office menu: hash-routed panes ─────────────── - const PANES = ['overview', 'line', 'campaigns', 'earn', 'earnings', 'wallet']; - const TITLES = { overview: 'Overview', line: 'My line', campaigns: 'Campaigns', + const PANES = ['overview', 'line', 'buy', 'campaigns', 'earn', 'earnings', 'wallet']; + const TITLES = { overview: 'Overview', line: 'My line', buy: 'Buy packages', campaigns: 'Campaigns', earn: 'Earn credits', earnings: 'Earnings', wallet: 'Wallet & account' }; function setPane(name) { if (!PANES.includes(name)) name = 'overview'; @@ -202,6 +202,43 @@ // defers the busy() lookup to click time (busy is declared below) function busy2(btn, fn) { return (...a) => busy(btn, fn)(...a); } + // ── in-dashboard package buying ── + const PKG = { 1: 'Micro', 2: 'Activation', 3: 'Builder', 4: 'Growth', 5: 'Leader' }; + async function loadBuyTiles() { + try { + const { products } = await (await fetch('/api/catalog')).json(); + const wrap = $('boTiles'); + wrap.innerHTML = ''; + for (const p of products) { + const bonus = p.creditAmount - p.priceCents; + const div = document.createElement('div'); + div.className = 'tile' + (p.priceCents === 5000 ? ' hot' : ''); + div.innerHTML = '
' + (PKG[p.id] || 'Package ' + p.id) + '
' + + '
$' + Math.round(p.priceCents / 100) + '
' + + '
' + p.creditAmount.toLocaleString() + ' credits
' + + '
' + (bonus > 0 ? '+' + bonus.toLocaleString() + ' bonus credits' : ' ') + '
' + + '
' + (p.costWei ? IAP.fmtPol(p.costWei) + ' POL right now' : 'paused') + '
' + + ''; + wrap.appendChild(div); + } + wrap.querySelectorAll('button[data-id]').forEach(b => b.addEventListener('click', async () => { + try { + b.disabled = true; + const spNow = await (await fetch('/api/sponsor')).json(); + IAP.status('Confirm the purchase in your wallet…'); + const r = await IAPWallet.buy(Number(b.dataset.id), spNow.sponsorId || 0, b.dataset.cost); + if (r.status !== '0x1' && r.receipt && r.receipt.status !== '0x1') throw new Error('Transaction reverted.'); + IAP.status('Purchase settled on-chain. Credits are in your account.', 'ok'); + await render(); + loadBuyTiles(); + } catch (e) { IAP.status('Purchase failed: ' + ((e && e.message) || e), 'bad'); } + finally { b.disabled = false; } + })); + } catch (e) {} + } + loadBuyTiles(); + // ── earn-by-viewing: daily ad set with dwell, then claim ── const earnState = { types: ['banner', 'text'], i: 0, timer: null }; async function earnRefresh() { diff --git a/public/contract.html b/public/contract.html index a2a84eb..7230098 100644 --- a/public/contract.html +++ b/public/contract.html @@ -5,7 +5,7 @@ The contract | InstantAdPay - +
@@ -129,8 +129,8 @@
Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.
- - - + + + diff --git a/public/index.html b/public/index.html index 8a85673..bcf6230 100644 --- a/public/index.html +++ b/public/index.html @@ -5,7 +5,7 @@ InstantAdPay: advertise and earn, locked in code - + @@ -399,9 +399,9 @@ - - - - + + + + diff --git a/public/ledger.html b/public/ledger.html index ddbf9ca..1b8d674 100644 --- a/public/ledger.html +++ b/public/ledger.html @@ -5,7 +5,7 @@ Live ledger | InstantAdPay - +
@@ -25,8 +25,8 @@
InstantAdPay · how it works · contract source ↗
- - - + + + diff --git a/public/my.html b/public/my.html index 2632fa7..83f444f 100644 --- a/public/my.html +++ b/public/my.html @@ -4,7 +4,7 @@ Member area | InstantAdPay - + @@ -54,6 +54,7 @@