Earn tab: progress hint shows at every stage (the claim-ready hint was unreachable); member guide /earning

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-12 17:41:13 -05:00
parent a6dcd02999
commit 1a83f4f2ff
4 changed files with 81 additions and 4 deletions
+6 -2
View File
@@ -1702,8 +1702,12 @@
+ '<button type="button" class="btn sec small" data-earnnext="campaigns">Launch a campaign with your ' + (st.earnedAvailable != null ? st.earnedAvailable : st.earned) + ' credits</button></div></div>'; + '<button type="button" class="btn sec small" data-earnnext="campaigns">Launch a campaign with your ' + (st.earnedAvailable != null ? st.earnedAvailable : st.earned) + ' credits</button></div></div>';
if (box) box.querySelectorAll('[data-earnnext]').forEach(b => b.addEventListener('click', () => { if (b.dataset.earnnext === 'campaigns') setPane('campaigns'); else setEarnSub('visits'); })); if (box) box.querySelectorAll('[data-earnnext]').forEach(b => b.addEventListener('click', () => { if (b.dataset.earnnext === 'campaigns') setPane('campaigns'); else setEarnSub('visits'); }));
if ($('earnStartBtn')) $('earnStartBtn').hidden = true; if ($('earnStartBtn')) $('earnStartBtn').hidden = true;
} else if ($('earnStartBtn')) $('earnStartBtn').hidden = false; } else {
else if (done) $('earnHint').textContent = 'Set complete. Claim your ' + st.claimCredits + ' credits' + (st.streakDay > 1 ? ' (streak day ' + st.streakDay + ')' : '') + '.'; if ($('earnStartBtn')) $('earnStartBtn').hidden = done; // set done: the claim button takes over
$('earnHint').textContent = done
? 'Set complete. Claim your ' + st.claimCredits + ' credits' + (st.streakDay > 1 ? ' (streak day ' + st.streakDay + ')' : '') + '.'
: (st.views ? (st.target - st.views) + ' more to go, then claim ' + st.claimCredits + ' credits' + (st.streakDay > 1 ? ' (streak day ' + st.streakDay + ')' : '') + '.' : 'View ' + st.target + ' ads to unlock the daily claim of ' + st.claimCredits + ' credits' + (st.streakDay > 1 ? ' (streak day ' + st.streakDay + ')' : '') + '.');
}
return st; return st;
} catch (e) { return null; } } catch (e) { return null; }
} }
+72
View File
@@ -0,0 +1,72 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>How earning works | InstantAdPay</title>
<meta name="description" content="How members earn ad credits on InstantAdPay: the daily set, the claim streak, verified visits, videos, inbox ads, the login bonus, and what to do with the credits.">
<meta name="robots" content="noindex">
<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="icon" type="image/png" href="/logo-icon.png">
<link rel="stylesheet" href="/assets/site.css?v=20260912b">
<style>
.eg{max-width:820px}
.eg h2{font-size:23px;margin:40px 0 10px;padding-top:18px;border-top:1px solid var(--line)}
.eg p,.eg li{max-width:68ch}
.eg ul,.eg ol{margin:0 0 14px 20px;padding:0} .eg li{margin:7px 0}
table{border-collapse:collapse;width:100%;max-width:560px;margin:10px 0 16px;font-variant-numeric:tabular-nums;font-size:15px}
th,td{text-align:left;padding:8px 10px;border-bottom:1px solid var(--line)} th{color:var(--muted);font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;font-weight:500}
td:last-child,th:last-child{text-align:right}
.rule{border-left:4px solid var(--mint);background:rgba(67,232,195,.07);padding:14px 18px;border-radius:0 12px 12px 0;margin:0 0 20px}
.rule b{font-family:var(--disp);display:block;margin-bottom:4px}
</style>
</head>
<body>
<div class="wrap eg">
<section class="hero" style="padding:60px 0 14px">
<p class="eyebrow">Member guide</p>
<h1>How earning works, <em>and what to do with it</em>.</h1>
<p class="lead">Every free way to earn ad credits, the claim streak, and the one thing that makes the credits worth anything: spending them on a campaign.</p>
</section>
<div class="rule"><b>One credit is one cent of ad delivery.</b> Credits are not money and cannot be withdrawn. They buy impressions, clicks and visits for your own campaigns across InstantAdPay and the partner network. Payouts in POL come only from packages people in your line buy.</div>
<h2>1. The daily set</h2>
<p>Earn credits &rsaquo; Watch ads. Five ads a day. Each one opens full screen, a 10-second countdown runs while you look, you pass a quick click-the-icon check, and you earn 1 credit. Finish all five and the Claim button appears.</p>
<h2>2. The claim streak</h2>
<p>The claim pays more the more days in a row you claim it. Miss a day and it restarts at day 1.</p>
<table>
<tr><th>Consecutive day</th><th>Claim pays</th></tr>
<tr><td>Day 1</td><td>5 credits</td></tr>
<tr><td>Day 2</td><td>7 credits</td></tr>
<tr><td>Day 3 and on</td><td>10 credits</td></tr>
<tr><td>Every 7th day in a row</td><td>25 credits</td></tr>
</table>
<p>The hint under the set always tells you which day you are on and what tomorrow's claim pays. Days are counted in UTC, so the set resets at 7 PM Central.</p>
<h2>3. After the set: verified visits</h2>
<p>When the set is claimed, the done screen offers verified visits: up to 20 a day, 1 credit each. You open a member's site in a new tab, stay for the dwell, and the visit counts. Each visit is unique per site per day, so it is 20 different sites, not one site 20 times.</p>
<h2>4. Videos and inbox ads</h2>
<ul>
<li><b>Videos.</b> Earn credits &rsaquo; Watch videos. You are credited only when the video plays to the end. Up to 6 a day, and the reward depends on the video's length.</li>
<li><b>Inbox solo ads.</b> Earn credits &rsaquo; Inbox Ads. Open the message, visit the advertiser's link, then claim 2 credits. Once per message.</li>
</ul>
<h2>5. The sign-in bonus and milestones</h2>
<p>Signing in pays 5 credits a day, rising by one for each consecutive day up to 10. Milestone badges pay too: Spark when payouts are on, Surge at your first qualifying buyer, Circuit at two, Nexus at five.</p>
<h2>6. Now spend it</h2>
<p>Credits sitting in your balance do nothing. Campaigns &rsaquo; New campaign: pick a banner or a text ad, give it a name and a budget in credits, point it at your own invite link or wall, and launch. Banner and text ads also push out to the partner network, so a 100-credit campaign is a hundred cents of real delivery. The done screen has a one-tap button for this after every claim.</p>
<p>Two things to know: a campaign reserves its whole budget the moment you start it, so your available balance drops right away and never surprises you later, and login ads are the one format that needs purchased credits.</p>
<p class="muted small" style="margin-top:30px">No income is guaranteed. Results depend on your effort. Cryptocurrency involves risk of loss. InstantAdPay sells advertising; it is not an investment.</p>
<footer>
<div>InstantAdPay · <a href="/my#earn">Earn credits</a> · <a href="/my#campaigns">Campaigns</a> · <a href="/my#training">back to Training</a></div>
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees.</div>
</footer>
</div>
<script src="/assets/common.js?v=20260912d"></script>
</body>
</html>
+1 -1
View File
@@ -915,7 +915,7 @@
<script src="/assets/common.js?v=20260912d"></script> <script src="/assets/common.js?v=20260912d"></script>
<script src="/assets/wallet.js?v=20260911a"></script> <script src="/assets/wallet.js?v=20260911a"></script>
<script src="/assets/promo.js?v=20260911a"></script> <script src="/assets/promo.js?v=20260911a"></script>
<script src="/assets/my.js?v=20260912h"></script> <script src="/assets/my.js?v=20260912i"></script>
<script src="/assets/chat.js?v=20260907l"></script> <script src="/assets/chat.js?v=20260907l"></script>
</body> </body>
</html> </html>
+2 -1
View File
@@ -28,7 +28,7 @@ const tank = require('./tank'); // holding tank: unsponsored free members, a
const legacy = require('./legacy'); // Faucet Wave / Tier One Ads bridge: welcome-back credits for listed emails const legacy = require('./legacy'); // Faucet Wave / Tier One Ads bridge: welcome-back credits for listed emails
const traffic = require('./traffic'); // public page views by referring domain (admin Traffic tab) const traffic = require('./traffic'); // public page views by referring domain (admin Traffic tab)
const promos = require('./promos'); // partner promo codes -> free ad credits (link ?promo=CODE or the dashboard box) const promos = require('./promos'); // partner promo codes -> free ad credits (link ?promo=CODE or the dashboard box)
const TRAFFIC_PAGES = new Set(['/', '/ledger', '/contract', '/shorts', '/plays', '/wallets', '/launch', '/partners']); const TRAFFIC_PAGES = new Set(['/', '/ledger', '/contract', '/shorts', '/plays', '/wallets', '/launch', '/partners', '/earning']);
let tankWaitCache = null; // dashboard: who is waiting for a sponsor (refreshed every minute) let tankWaitCache = null; // dashboard: who is waiting for a sponsor (refreshed every minute)
const geo = require('./geo'); // viewer country -> tier (DB-IP lite), for campaign targeting const geo = require('./geo'); // viewer country -> tier (DB-IP lite), for campaign targeting
const burner = require('./burner'); // automatic on-chain credit burns (inert without ENGINE_KEY) const burner = require('./burner'); // automatic on-chain credit burns (inert without ENGINE_KEY)
@@ -2144,6 +2144,7 @@ const server = http.createServer(async (req, res) => {
if (p === '/shorts') return sendFile(res, path.join(PUBLIC_DIR, 'shorts.html')); if (p === '/shorts') return sendFile(res, path.join(PUBLIC_DIR, 'shorts.html'));
if (p === '/plays') return sendFile(res, path.join(PUBLIC_DIR, 'plays.html')); if (p === '/plays') return sendFile(res, path.join(PUBLIC_DIR, 'plays.html'));
if (p === '/partners') return sendFile(res, path.join(PUBLIC_DIR, 'partners.html')); // site-owner kit (Marty, 2026-09-12) if (p === '/partners') return sendFile(res, path.join(PUBLIC_DIR, 'partners.html')); // site-owner kit (Marty, 2026-09-12)
if (p === '/earning') return sendFile(res, path.join(PUBLIC_DIR, 'earning.html')); // member guide: how earning works (2026-09-12)
if (p === '/wallets') return sendFile(res, path.join(PUBLIC_DIR, 'wallets.html')); if (p === '/wallets') return sendFile(res, path.join(PUBLIC_DIR, 'wallets.html'));
if (p === '/launch') return sendFile(res, path.join(PUBLIC_DIR, 'launch.html')); if (p === '/launch') return sendFile(res, path.join(PUBLIC_DIR, 'launch.html'));
if (/^\/view\/[a-f0-9]{32}$/.test(p)) return sendFile(res, path.join(PUBLIC_DIR, 'view.html')); if (/^\/view\/[a-f0-9]{32}$/.test(p)) return sendFile(res, path.join(PUBLIC_DIR, 'view.html'));