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 <noreply@anthropic.com>
This commit is contained in:
+39
-2
@@ -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 = '<div class="name">' + (PKG[p.id] || 'Package ' + p.id) + '</div>'
|
||||
+ '<div class="price">$' + Math.round(p.priceCents / 100) + '</div>'
|
||||
+ '<div class="cr">' + p.creditAmount.toLocaleString() + ' credits</div>'
|
||||
+ '<div class="bonus">' + (bonus > 0 ? '+' + bonus.toLocaleString() + ' bonus credits' : ' ') + '</div>'
|
||||
+ '<div class="pol">' + (p.costWei ? IAP.fmtPol(p.costWei) + ' POL right now' : 'paused') + '</div>'
|
||||
+ '<button class="btn small" data-id="' + p.id + '" data-cost="' + (p.costWei || '') + '"'
|
||||
+ (p.costWei ? '' : ' disabled') + '>Buy</button>';
|
||||
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() {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<title>The contract | InstantAdPay</title>
|
||||
<meta name="description" content="Plain-language review of the InstantAdPay settlement contract: what it does, what nobody can change, what the operator can and cannot touch, and how to verify all of it yourself.">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||
<link rel="stylesheet" href="/assets/site.css?v=20260905d">
|
||||
<link rel="stylesheet" href="/assets/site.css?v=20260905e">
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
@@ -129,8 +129,8 @@
|
||||
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.</div>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="/assets/common.js?v=20260905d"></script>
|
||||
<script src="/assets/contract.js?v=20260905d"></script>
|
||||
<script src="/assets/chat.js?v=20260905d"></script>
|
||||
<script src="/assets/common.js?v=20260905e"></script>
|
||||
<script src="/assets/contract.js?v=20260905e"></script>
|
||||
<script src="/assets/chat.js?v=20260905e"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+5
-5
@@ -5,7 +5,7 @@
|
||||
<title>InstantAdPay: advertise and earn, locked in code</title>
|
||||
<meta name="description" content="Real ad packages with instant on-chain settlement. Every purchase pays the sponsor line in the same transaction, verifiable by anyone on the live ledger.">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||
<link rel="stylesheet" href="/assets/site.css?v=20260905d">
|
||||
<link rel="stylesheet" href="/assets/site.css?v=20260905e">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -399,9 +399,9 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script src="/assets/common.js?v=20260905d"></script>
|
||||
<script src="/assets/wallet.js?v=20260905d"></script>
|
||||
<script src="/assets/home.js?v=20260905d"></script>
|
||||
<script src="/assets/chat.js?v=20260905d"></script>
|
||||
<script src="/assets/common.js?v=20260905e"></script>
|
||||
<script src="/assets/wallet.js?v=20260905e"></script>
|
||||
<script src="/assets/home.js?v=20260905e"></script>
|
||||
<script src="/assets/chat.js?v=20260905e"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+4
-4
@@ -5,7 +5,7 @@
|
||||
<title>Live ledger | InstantAdPay</title>
|
||||
<meta name="description" content="Every purchase, payout, and pass-up on InstantAdPay, streamed straight from the blockchain with a verify link on every line.">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||
<link rel="stylesheet" href="/assets/site.css?v=20260905d">
|
||||
<link rel="stylesheet" href="/assets/site.css?v=20260905e">
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
@@ -25,8 +25,8 @@
|
||||
<div>InstantAdPay · <a href="/">how it works</a> · <a id="contractLink" href="#" target="_blank" rel="noopener">contract source ↗</a></div>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="/assets/common.js?v=20260905d"></script>
|
||||
<script src="/assets/ledger.js?v=20260905d"></script>
|
||||
<script src="/assets/chat.js?v=20260905d"></script>
|
||||
<script src="/assets/common.js?v=20260905e"></script>
|
||||
<script src="/assets/ledger.js?v=20260905e"></script>
|
||||
<script src="/assets/chat.js?v=20260905e"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+15
-5
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Member area | InstantAdPay</title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||
<link rel="stylesheet" href="/assets/site.css?v=20260905d">
|
||||
<link rel="stylesheet" href="/assets/site.css?v=20260905e">
|
||||
</head>
|
||||
<body class="bo-body">
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
<nav class="bo-menu" aria-label="Member menu">
|
||||
<button data-pane="overview" class="on" type="button"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="8" height="8" rx="2"/><rect x="13" y="3" width="8" height="8" rx="2"/><rect x="3" y="13" width="8" height="8" rx="2"/><rect x="13" y="13" width="8" height="8" rx="2"/></svg>Overview</button>
|
||||
<button data-pane="line" type="button"><svg viewBox="0 0 24 24"><circle cx="12" cy="7" r="3.2"/><circle cx="5" cy="17" r="2.6"/><circle cx="19" cy="17" r="2.6"/><path d="M12 10v3M12 13l-5 2M12 13l5 2"/></svg>My line</button>
|
||||
<button data-pane="buy" type="button"><svg viewBox="0 0 24 24"><circle cx="9" cy="20" r="1.6"/><circle cx="17" cy="20" r="1.6"/><path d="M3 4h2l2.4 11.2A2 2 0 0 0 9.4 17h8.2a2 2 0 0 0 2-1.6L21 8H6"/></svg>Buy packages</button>
|
||||
<button data-pane="campaigns" type="button"><svg viewBox="0 0 24 24"><path d="M3 11l14-5v12L3 13v-2z"/><path d="M17 8a4 4 0 0 1 0 8M7 13v5a2 2 0 0 0 4 0v-3"/></svg>Campaigns</button>
|
||||
<button data-pane="earn" type="button"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5v9M9 10c0-1.1 1.3-1.8 3-1.8s3 .7 3 1.8-1.3 1.6-3 1.8-3 .7-3 1.8 1.3 1.8 3 1.8 3-.7 3-1.8"/></svg>Earn credits</button>
|
||||
<button data-pane="earnings" type="button"><svg viewBox="0 0 24 24"><path d="M4 17l5-5 4 3 7-8"/><path d="M14 7h6v6"/></svg>Earnings</button>
|
||||
@@ -128,6 +129,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pane" id="pane-buy" hidden>
|
||||
<div class="card">
|
||||
<h3>Buy an ad package</h3>
|
||||
<p class="muted small">Priced in dollars, settled from your wallet at the live rate. Credits mint
|
||||
to this account instantly, and every payout in your sponsor line lands the moment you confirm.</p>
|
||||
<div class="tiles" id="boTiles"><div class="tile"><span class="muted small">Loading live prices…</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pane" id="pane-campaigns" hidden>
|
||||
<div class="card" id="campGate" hidden>
|
||||
<h3>Campaigns unlock with your first package</h3>
|
||||
@@ -230,9 +240,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/common.js?v=20260905d"></script>
|
||||
<script src="/assets/wallet.js?v=20260905d"></script>
|
||||
<script src="/assets/my.js?v=20260905d"></script>
|
||||
<script src="/assets/chat.js?v=20260905d"></script>
|
||||
<script src="/assets/common.js?v=20260905e"></script>
|
||||
<script src="/assets/wallet.js?v=20260905e"></script>
|
||||
<script src="/assets/my.js?v=20260905e"></script>
|
||||
<script src="/assets/chat.js?v=20260905e"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user