Campaigns: gold available-to-spend banner + where-your-ads-run (incl. Network Ad Space); Wallet: live POL balances; Earn credits: done-for-today mark
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
<title>Admin | InstantAdPay</title>
|
<title>Admin | InstantAdPay</title>
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
<style>
|
<style>
|
||||||
.adm-table th,.adm-table td{padding:8px 10px;text-align:left;vertical-align:top;border-bottom:1px solid var(--line);font-size:13.5px}
|
.adm-table th,.adm-table td{padding:8px 10px;text-align:left;vertical-align:top;border-bottom:1px solid var(--line);font-size:13.5px}
|
||||||
.adm-table th{color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.08em}
|
.adm-table th{color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.08em}
|
||||||
|
|||||||
+34
-3
@@ -582,6 +582,12 @@
|
|||||||
if (r.bannerSizes && $('cSize') && !$('cSize').options.length)
|
if (r.bannerSizes && $('cSize') && !$('cSize').options.length)
|
||||||
$('cSize').innerHTML = r.bannerSizes.map(s => '<option value="' + s.id + '">' + s.label + '</option>').join('');
|
$('cSize').innerHTML = r.bannerSizes.map(s => '<option value="' + s.id + '">' + s.label + '</option>').join('');
|
||||||
soloHint();
|
soloHint();
|
||||||
|
if ($('spendBanner')) {
|
||||||
|
$('spendBanner').hidden = false;
|
||||||
|
$('spendBig').textContent = r.availableCredits.toLocaleString();
|
||||||
|
$('spendSub').textContent = '= $' + (r.availableCredits / 100).toLocaleString(undefined, { maximumFractionDigits: 2 }) + ' of ad delivery' + (r.earnedCredits ? ' · ' + r.purchasedCredits.toLocaleString() + ' purchased + ' + r.earnedCredits.toLocaleString() + ' earned by viewing' : '') + (r.positionCount > 1 ? ' · pooled across ' + r.positionCount + ' positions (largest single position ' + (r.largestPosition || 0).toLocaleString() + ')' : '');
|
||||||
|
$('spendRates').innerHTML = [['Banner', r.rates.bannerCreditsPerBatch + ' cr / ' + r.rates.bannerBatch + ' views'], ['Text', r.rates.textCreditsPerBatch + ' cr / ' + r.rates.textBatch + ' views'], ['Login', r.rates.loginCreditsPerDay + ' cr / day'], ['Solo', r.rates.soloCostPerRecipient + ' cr / delivery'], ['Featured', (r.rates.featuredPerDay || 40) + ' cr / day'], ['Visit', (r.rates.visitCostPerVisit || 3) + ' cr / visit']].map(x => '<span><b>' + x[0] + '</b> ' + x[1] + '</span>').join('');
|
||||||
|
}
|
||||||
$('rateLine').textContent = 'Available to spend: ' + r.availableCredits.toLocaleString()
|
$('rateLine').textContent = 'Available to spend: ' + r.availableCredits.toLocaleString()
|
||||||
+ (r.earnedCredits ? ' (' + r.purchasedCredits.toLocaleString() + ' purchased + ' + r.earnedCredits + ' earned)' : '')
|
+ (r.earnedCredits ? ' (' + r.purchasedCredits.toLocaleString() + ' purchased + ' + r.earnedCredits + ' earned)' : '')
|
||||||
+ ' credits · rates: banner ' + r.rates.bannerCreditsPerBatch + 'cr/' + r.rates.bannerBatch
|
+ ' credits · rates: banner ' + r.rates.bannerCreditsPerBatch + 'cr/' + r.rates.bannerBatch
|
||||||
@@ -672,7 +678,17 @@
|
|||||||
if (raw.hidden) { raw.value = ed.innerHTML; raw.hidden = false; ed.hidden = true; $('edRawBtn').textContent = 'Visual'; }
|
if (raw.hidden) { raw.value = ed.innerHTML; raw.hidden = false; ed.hidden = true; $('edRawBtn').textContent = 'Visual'; }
|
||||||
else { ed.innerHTML = raw.value; ed.hidden = false; raw.hidden = true; $('edRawBtn').textContent = 'Raw text'; }
|
else { ed.innerHTML = raw.value; ed.hidden = false; raw.hidden = true; $('edRawBtn').textContent = 'Raw text'; }
|
||||||
});
|
});
|
||||||
|
const WHERE = { banner: 'Runs in the ad viewer, on the home page, the live ledger, every Overview, the sidebar tile, and out in the Network Ad Space rotation across the wider network.',
|
||||||
|
text: 'Runs in the ad viewer, the live ledger text slot, and out in the Network Ad Space rotation.',
|
||||||
|
login: 'Full screen for every member who signs in, ten seconds, once a day per member. Opens in a fresh tab, so any working page qualifies.',
|
||||||
|
solo: 'Delivered into member inboxes under Earn credits. Each read is timed and rewarded, so it gets opened.',
|
||||||
|
video: 'Plays in Watch videos and the Shorts feed under Earn credits. You pay only for completed watches.',
|
||||||
|
featured: 'Your headline and link in the Featured strip on every member Overview for the days you book.',
|
||||||
|
visits: 'A distinct member opens your site in a new tab, stays eight seconds and passes a check. Nobody counts twice.' };
|
||||||
|
const whereHint = () => { const el = $('cWhere'); if (el) el.textContent = WHERE[$('cType').value] || ''; };
|
||||||
|
whereHint();
|
||||||
$('cType').addEventListener('change', () => {
|
$('cType').addEventListener('change', () => {
|
||||||
|
whereHint();
|
||||||
const t = $('cType').value;
|
const t = $('cType').value;
|
||||||
$('cImageRow').hidden = t !== 'banner'; // only banners carry a creative; login frames its URL
|
$('cImageRow').hidden = t !== 'banner'; // only banners carry a creative; login frames its URL
|
||||||
$('cSizeRow').hidden = t !== 'banner';
|
$('cSizeRow').hidden = t !== 'banner';
|
||||||
@@ -1323,15 +1339,26 @@
|
|||||||
const rows = list.map((p, i) => '<div class="lin-row"><span class="nm">Position ' + (i + 2) + ' <span class="mono">' + short(p.address) + '</span></span>'
|
const rows = list.map((p, i) => '<div class="lin-row"><span class="nm">Position ' + (i + 2) + ' <span class="mono">' + short(p.address) + '</span></span>'
|
||||||
+ '<span class="id">' + (p.memberId ? '#' + p.memberId : 'not on-chain yet') + '</span>'
|
+ '<span class="id">' + (p.memberId ? '#' + p.memberId : 'not on-chain yet') + '</span>'
|
||||||
+ '<span class="earn' + (p.counted ? ' on' : '') + '">' + (p.counted ? 'counts as a qualifying buyer' : p.memberId ? 'registered, buy $20+ to count' : 'buy a $20+ package to register it') + '</span>'
|
+ '<span class="earn' + (p.counted ? ' on' : '') + '">' + (p.counted ? 'counts as a qualifying buyer' : p.memberId ? 'registered, buy $20+ to count' : 'buy a $20+ package to register it') + '</span>'
|
||||||
+ '<span class="dt">' + (p.credits || 0).toLocaleString() + ' credits</span>'
|
+ '<span class="dt">' + (p.credits || 0).toLocaleString() + ' credits' + (p.balanceWei != null ? ' · ' + (Number(BigInt(p.balanceWei) / 10n ** 14n) / 10000).toLocaleString(undefined, { maximumFractionDigits: 2 }) + ' POL' : '') + '</span>'
|
||||||
+ (!p.memberId ? '<button class="btn sec small" type="button" data-unlink="' + p.address + '">Unlink</button>' : '')
|
+ (!p.memberId ? '<button class="btn sec small" type="button" data-unlink="' + p.address + '">Unlink</button>' : '')
|
||||||
+ '</div>').join('');
|
+ '</div>').join('');
|
||||||
const mainRow = r.main && r.main.address ? '<div class="lin-row"><span class="nm">Position 1 · main <span class="mono">' + short(r.main.address) + '</span></span>'
|
const mainRow = r.main && r.main.address ? '<div class="lin-row"><span class="nm">Position 1 · main <span class="mono">' + short(r.main.address) + '</span></span>'
|
||||||
+ '<span class="id">' + (r.main.memberId ? '#' + r.main.memberId : 'payouts not on yet') + '</span>'
|
+ '<span class="id">' + (r.main.memberId ? '#' + r.main.memberId : 'payouts not on yet') + '</span>'
|
||||||
+ '<span class="earn on">' + (r.main.buyerCount || 0) + ' qualifying buyer(s)</span>'
|
+ '<span class="earn on">' + (r.main.buyerCount || 0) + ' qualifying buyer(s)</span>'
|
||||||
+ '<span class="dt">' + (r.main.credits || 0).toLocaleString() + ' credits</span></div>' : '';
|
+ '<span class="dt">' + (r.main.credits || 0).toLocaleString() + ' credits' + (r.main.balanceWei != null ? ' · ' + (Number(BigInt(r.main.balanceWei) / 10n ** 14n) / 10000).toLocaleString(undefined, { maximumFractionDigits: 2 }) + ' POL' : '') + '</span></div>' : '';
|
||||||
const html = mainRow + rows + (list.length ? '<p class="muted small" style="margin:8px 0 0">Pooled credits: <b>' + (r.totalCredits || 0).toLocaleString() + '</b>. A campaign budget spends from one position at a time.</p>' : '');
|
const html = mainRow + rows + (list.length ? '<p class="muted small" style="margin:8px 0 0">Pooled credits: <b>' + (r.totalCredits || 0).toLocaleString() + '</b>. A campaign budget spends from one position at a time.</p>' : '');
|
||||||
if ($('qsList')) $('qsList').innerHTML = html;
|
if ($('qsList')) $('qsList').innerHTML = html;
|
||||||
|
// Wallet tab: live POL balance of the linked wallet, and which package it covers
|
||||||
|
const wb = $('walletBal');
|
||||||
|
if (wb && r.main && r.main.address && r.main.balanceWei != null) {
|
||||||
|
const polN = Number(BigInt(r.main.balanceWei) / 10n ** 14n) / 10000;
|
||||||
|
const usd = r.polUsd ? polN * r.polUsd : 0;
|
||||||
|
const pkgs = [5, 20, 50, 100, 250];
|
||||||
|
const covers = r.polUsd ? pkgs.filter(p => usd >= p * 1.06 + 0.05) : [];
|
||||||
|
wb.hidden = false;
|
||||||
|
wb.innerHTML = 'Wallet balance: <b class="mono">' + polN.toLocaleString(undefined, { maximumFractionDigits: 2 }) + ' POL</b>' + (usd ? ' (about $' + usd.toLocaleString(undefined, { maximumFractionDigits: 0 }) + ')' : '')
|
||||||
|
+ (r.polUsd ? '<br><span class="muted">' + (covers.length ? 'Enough for the $' + covers[covers.length - 1] + ' package with gas to spare.' : 'Not enough for the $5 package yet. Buy POL with a card on the Buy packages tab, or send POL to this wallet.') + (covers.length && covers.length < pkgs.length ? ' Top up for the $' + pkgs[covers.length] + ' package.' : '') + '</span>' : '');
|
||||||
|
}
|
||||||
if ($('posList')) $('posList').innerHTML = html;
|
if ($('posList')) $('posList').innerHTML = html;
|
||||||
if ($('posCard')) $('posCard').hidden = !list.length;
|
if ($('posCard')) $('posCard').hidden = !list.length;
|
||||||
// "Buy from" picker: main + every position
|
// "Buy from" picker: main + every position
|
||||||
@@ -1461,7 +1488,11 @@
|
|||||||
$('earnBalance').textContent = st.earned + ' earned credits';
|
$('earnBalance').textContent = st.earned + ' earned credits';
|
||||||
const done = st.views >= st.target;
|
const done = st.views >= st.target;
|
||||||
$('earnClaimBtn').hidden = !(done && !st.claimed);
|
$('earnClaimBtn').hidden = !(done && !st.claimed);
|
||||||
if (st.claimed) $('earnHint').textContent = 'Claimed for today. Come back tomorrow, or put those credits to work in Campaigns.';
|
if (st.claimed) {
|
||||||
|
$('earnHint').textContent = 'Claimed for today. Come back tomorrow, or put those credits to work in Campaigns.';
|
||||||
|
const box = $('earnAdBox'); if (box && !box.querySelector('.done-big')) box.innerHTML = '<div class="done-big"><span class="tick">✓</span><b>Ads done for today</b><span class="muted small">Today\'s set is viewed and claimed. Fresh ads tomorrow.</span></div>';
|
||||||
|
if ($('earnStartBtn')) $('earnStartBtn').hidden = true;
|
||||||
|
} else if ($('earnStartBtn')) $('earnStartBtn').hidden = false;
|
||||||
else if (done) $('earnHint').textContent = 'Set complete. Claim your ' + st.claimCredits + ' credits.';
|
else if (done) $('earnHint').textContent = 'Set complete. Claim your ' + st.claimCredits + ' credits.';
|
||||||
return st;
|
return st;
|
||||||
} catch (e) { return null; }
|
} catch (e) { return null; }
|
||||||
|
|||||||
@@ -202,6 +202,16 @@ tr:last-child td{border-bottom:0}
|
|||||||
.feed .tx a{color:var(--muted);font-size:12px}
|
.feed .tx a{color:var(--muted);font-size:12px}
|
||||||
.badge{display:inline-block;background:var(--mint-soft);color:var(--mint);border:1px solid rgba(67,232,195,.35);
|
.badge{display:inline-block;background:var(--mint-soft);color:var(--mint);border:1px solid rgba(67,232,195,.35);
|
||||||
border-radius:999px;padding:3px 13px;font-size:12px;font-weight:700}
|
border-radius:999px;padding:3px 13px;font-size:12px;font-weight:700}
|
||||||
|
.spend-banner{background:linear-gradient(160deg,rgba(242,201,76,.14),rgba(242,201,76,.04));border-color:rgba(242,201,76,.55);text-align:center;padding:22px 20px}
|
||||||
|
.spend-banner .lbl{font-family:var(--disp);font-size:13px;letter-spacing:.14em;text-transform:uppercase;color:#f2c94c}
|
||||||
|
.spend-banner .big{font-family:var(--disp);font-size:clamp(40px,6vw,64px);font-weight:800;color:#f2c94c;line-height:1.05;margin:6px 0 4px;font-variant-numeric:tabular-nums}
|
||||||
|
.spend-banner .big .unit{font-size:20px;font-weight:700;color:var(--ink)}
|
||||||
|
.spend-banner .sub{color:var(--ink);font-size:15px}
|
||||||
|
.spend-banner .rates{display:flex;gap:8px 18px;flex-wrap:wrap;justify-content:center;margin-top:12px;font-size:12.5px;color:var(--muted)}
|
||||||
|
.spend-banner .rates b{color:var(--ink)}
|
||||||
|
.done-big{display:flex;flex-direction:column;align-items:center;gap:6px;padding:26px 16px;text-align:center}
|
||||||
|
.done-big .tick{width:84px;height:84px;border-radius:50%;display:grid;place-items:center;font-size:48px;font-weight:800;color:var(--mint-ink);background:var(--mint);box-shadow:0 0 0 10px rgba(67,232,195,.15),0 10px 30px rgba(67,232,195,.35)}
|
||||||
|
.done-big b{font-family:var(--disp);font-size:22px;margin-top:8px}
|
||||||
.badge.amber{background:rgba(139,166,156,.1);border-color:rgba(139,166,156,.4);color:var(--muted)}
|
.badge.amber{background:rgba(139,166,156,.1);border-color:rgba(139,166,156,.4);color:var(--muted)}
|
||||||
/* faq */
|
/* faq */
|
||||||
details{border:1px solid var(--line);border-radius:14px;margin:0 0 10px;background:var(--panel)}
|
details{border:1px solid var(--line);border-radius:14px;margin:0 0 10px;background:var(--panel)}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<meta name="theme-color" content="#043b2f">
|
<meta name="theme-color" content="#043b2f">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<title>Disclaimer | InstantAdPay</title>
|
<title>Disclaimer | InstantAdPay</title>
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<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=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="nav"></div>
|
<div id="nav"></div>
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@
|
|||||||
<meta name="theme-color" content="#043b2f">
|
<meta name="theme-color" content="#043b2f">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
<title>You're invited | InstantAdPay</title>
|
<title>You're invited | InstantAdPay</title>
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
<style>
|
<style>
|
||||||
.jn-nav{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:16px 0}
|
.jn-nav{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:16px 0}
|
||||||
.jn-hero{padding:34px 0 10px;text-align:left}
|
.jn-hero{padding:34px 0 10px;text-align:left}
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@
|
|||||||
<meta name="theme-color" content="#043b2f">
|
<meta name="theme-color" content="#043b2f">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
|
|||||||
+25
-3
@@ -5,7 +5,7 @@
|
|||||||
<title>Member area | InstantAdPay</title>
|
<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="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
</head>
|
</head>
|
||||||
<body class="bo-body">
|
<body class="bo-body">
|
||||||
|
|
||||||
@@ -388,6 +388,26 @@
|
|||||||
<p class="muted small">Campaigns spend the on-chain credits a package mints. Grab any package on the
|
<p class="muted small">Campaigns spend the on-chain credits a package mints. Grab any package on the
|
||||||
<a href="/#ladder-h">home page</a> and this tab turns into your campaign manager.</p>
|
<a href="/#ladder-h">home page</a> and this tab turns into your campaign manager.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card spend-banner" id="spendBanner" hidden>
|
||||||
|
<div class="lbl">Available to spend</div>
|
||||||
|
<div class="big"><span id="spendBig">0</span> <span class="unit">credits</span></div>
|
||||||
|
<div class="sub" id="spendSub"></div>
|
||||||
|
<div class="rates" id="spendRates"></div>
|
||||||
|
</div>
|
||||||
|
<div class="card" id="whereCard">
|
||||||
|
<h3>Where your ads run</h3>
|
||||||
|
<p class="muted small">Every format has its own surfaces inside InstantAdPay, and banner and text ads are also pushed into <b>Network Ad Space</b>, the Crypto Team Build Network's ad rotation that runs across the network's other member sites and tools. Impressions delivered out there are reconciled into your campaign stats here, so one budget works the whole network.</p>
|
||||||
|
<div class="tablewrap"><table class="small" id="whereTable">
|
||||||
|
<tr><th>Format</th><th>Shows up on</th></tr>
|
||||||
|
<tr><td>Banner</td><td>The ad viewer members open to earn (10-second dwell plus a human check), the home page, the live ledger, every member's Overview, the member-area sidebar tile, and the Network Ad Space rotation across the wider network.</td></tr>
|
||||||
|
<tr><td>Text ad</td><td>The ad viewer, the live ledger's text slot, and the Network Ad Space rotation.</td></tr>
|
||||||
|
<tr><td>Login ad</td><td>Full screen for every member who signs in, ten seconds, once a day per member.</td></tr>
|
||||||
|
<tr><td>Solo ad</td><td>Member inboxes under Earn credits, each read timed and rewarded, so the message actually gets opened.</td></tr>
|
||||||
|
<tr><td>Video ad</td><td>Watch videos and the Shorts feed under Earn credits, credited only on a completed watch.</td></tr>
|
||||||
|
<tr><td>Featured link</td><td>The Featured strip at the top of every member's Overview, for one, two or seven days.</td></tr>
|
||||||
|
<tr><td>Verified visits</td><td>A distinct member opens your site in a new tab, stays eight seconds and passes a check. Nobody counts twice.</td></tr>
|
||||||
|
</table></div>
|
||||||
|
</div>
|
||||||
<div class="card" id="campaignCard" hidden>
|
<div class="card" id="campaignCard" hidden>
|
||||||
<h3>Your ad campaigns</h3>
|
<h3>Your ad campaigns</h3>
|
||||||
<p class="muted small" id="rateLine">…</p>
|
<p class="muted small" id="rateLine">…</p>
|
||||||
@@ -403,6 +423,7 @@
|
|||||||
<option value="featured">Featured link (rotation)</option>
|
<option value="featured">Featured link (rotation)</option>
|
||||||
<option value="visits">Verified visits (guaranteed unique)</option>
|
<option value="visits">Verified visits (guaranteed unique)</option>
|
||||||
</select></p>
|
</select></p>
|
||||||
|
<p class="small muted" id="cWhere" style="margin:-4px 0 10px"></p>
|
||||||
<p><input id="cName" placeholder="Campaign name" style="width:100%"></p>
|
<p><input id="cName" placeholder="Campaign name" style="width:100%"></p>
|
||||||
<p id="cBudgetRow"><input id="cBudget" type="number" placeholder="Budget (credits)" min="10" style="width:100%"></p>
|
<p id="cBudgetRow"><input id="cBudget" type="number" placeholder="Budget (credits)" min="10" style="width:100%"></p>
|
||||||
</div>
|
</div>
|
||||||
@@ -785,7 +806,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid c2">
|
<div class="grid c2">
|
||||||
<div class="card"><h3>Your account</h3>
|
<div class="card"><h3>Your account</h3>
|
||||||
<p id="posLine" class="muted small">…</p></div>
|
<p id="posLine" class="muted small">…</p>
|
||||||
|
<p id="walletBal" class="small" hidden></p></div>
|
||||||
<div class="card"><h3>Ad credits</h3>
|
<div class="card"><h3>Ad credits</h3>
|
||||||
<p class="mono" style="font-size:26px;margin:0" id="creditLine">0</p>
|
<p class="mono" style="font-size:26px;margin:0" id="creditLine">0</p>
|
||||||
<p class="muted small">1 credit = 1 cent of ad delivery across the network. Recorded on-chain. Only your campaigns can spend them.</p></div>
|
<p class="muted small">1 credit = 1 cent of ad delivery across the network. Recorded on-chain. Only your campaigns can spend them.</p></div>
|
||||||
@@ -835,7 +857,7 @@
|
|||||||
<script src="/assets/common.js?v=20260910a"></script>
|
<script src="/assets/common.js?v=20260910a"></script>
|
||||||
<script src="/assets/wallet.js?v=20260910a"></script>
|
<script src="/assets/wallet.js?v=20260910a"></script>
|
||||||
<script src="/assets/promo.js?v=20260909b"></script>
|
<script src="/assets/promo.js?v=20260909b"></script>
|
||||||
<script src="/assets/my.js?v=20260910d"></script>
|
<script src="/assets/my.js?v=20260910f"></script>
|
||||||
<script src="/assets/chat.js?v=20260907l"></script>
|
<script src="/assets/chat.js?v=20260907l"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
<meta name="theme-color" content="#043b2f">
|
<meta name="theme-color" content="#043b2f">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
<style>
|
<style>
|
||||||
.pl-rule{border-left:4px solid #f2c94c;background:rgba(242,201,76,.08);padding:16px 20px;border-radius:0 12px 12px 0;margin:0 0 28px}
|
.pl-rule{border-left:4px solid #f2c94c;background:rgba(242,201,76,.08);padding:16px 20px;border-radius:0 12px 12px 0;margin:0 0 28px}
|
||||||
.pl-rule b{font-family:var(--disp);font-size:17px;display:block;margin-bottom:6px}
|
.pl-rule b{font-family:var(--disp);font-size:17px;display:block;margin-bottom:6px}
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
<title>Privacy Policy | InstantAdPay</title>
|
<title>Privacy Policy | InstantAdPay</title>
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<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=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="nav"></div>
|
<div id="nav"></div>
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
<title>Shorts | InstantAdPay</title>
|
<title>Shorts | InstantAdPay</title>
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
<style>
|
<style>
|
||||||
html,body{height:100%;margin:0;overflow:hidden;background:#000}
|
html,body{height:100%;margin:0;overflow:hidden;background:#000}
|
||||||
.sh{position:fixed;inset:0;display:flex;flex-direction:column;background:#000;color:var(--ink,#e8fff7)}
|
.sh{position:fixed;inset:0;display:flex;flex-direction:column;background:#000;color:var(--ink,#e8fff7)}
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
<title>Terms of Service | InstantAdPay</title>
|
<title>Terms of Service | InstantAdPay</title>
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<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=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="nav"></div>
|
<div id="nav"></div>
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
<title>Transaction | InstantAdPay</title>
|
<title>Transaction | InstantAdPay</title>
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="nav"></div>
|
<div id="nav"></div>
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Viewing ad — InstantAdPay</title>
|
<title>Viewing ad — InstantAdPay</title>
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
<style>
|
<style>
|
||||||
html,body{height:100%;margin:0;overflow:hidden}
|
html,body{height:100%;margin:0;overflow:hidden}
|
||||||
.vw{display:flex;flex-direction:column;height:100vh;height:100dvh;background:var(--bg,#04110c);color:var(--ink,#e8fff7)}
|
.vw{display:flex;flex-direction:column;height:100vh;height:100dvh;background:var(--bg,#04110c);color:var(--ink,#e8fff7)}
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
<!--OG-->
|
<!--OG-->
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||||
<link rel="icon" type="image/png" href="/logo-icon.png">
|
<link rel="icon" type="image/png" href="/logo-icon.png">
|
||||||
<link rel="stylesheet" href="/assets/site.css?v=20260910b">
|
<link rel="stylesheet" href="/assets/site.css?v=20260910d">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="nav"></div>
|
<div id="nav"></div>
|
||||||
|
|||||||
@@ -868,7 +868,12 @@ const server = http.createServer(async (req, res) => {
|
|||||||
try { main.credits = await ads.availableCredits(mainId); } catch (e) {}
|
try { main.credits = await ads.availableCredits(mainId); } catch (e) {}
|
||||||
try { main.buyerCount = (await chain.member(mainId)).buyerCount; } catch (e) {}
|
try { main.buyerCount = (await chain.member(mainId)).buyerCount; } catch (e) {}
|
||||||
}
|
}
|
||||||
return json(res, 200, { main, positions: out, totalCredits: main.credits + out.reduce((n, r) => n + r.credits, 0) });
|
// live POL balances (the link signature proved the wallet is theirs) + a POL/USD rate from the catalog
|
||||||
|
const bal = async a => { try { return BigInt(await chain.rpc('eth_getBalance', [a, 'latest'])).toString(); } catch (e) { return null; } };
|
||||||
|
if (main.address) main.balanceWei = await bal(main.address);
|
||||||
|
for (const row of out) row.balanceWei = await bal(row.address);
|
||||||
|
let polUsd = 0; try { const cat = await chain.catalog(); const pk = cat.find(x => x.costWei); if (pk) polUsd = (pk.priceCents / 100) / (Number(BigInt(pk.costWei)) / 1e18); } catch (e) {}
|
||||||
|
return json(res, 200, { main, positions: out, polUsd, totalCredits: main.credits + out.reduce((n, r) => n + r.credits, 0) });
|
||||||
}
|
}
|
||||||
if (p === '/api/my/positions/remove' && req.method === 'POST') {
|
if (p === '/api/my/positions/remove' && req.method === 'POST') {
|
||||||
const s = await auth.fromRequest(req);
|
const s = await auth.fromRequest(req);
|
||||||
|
|||||||
Reference in New Issue
Block a user