Overview: Getting-started stepper (username, link wallet, switch on payouts, first package) with one guided button per step; soft nudge, collapsible, never a gate

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-14 05:53:02 -05:00
parent 825d0de6c3
commit b09e5dce8b
4 changed files with 54 additions and 2 deletions
+34
View File
@@ -472,12 +472,45 @@
$('lbList').innerHTML = h; $('lbCard').hidden = false;
} catch (e) {}
}
// Getting-started stepper: username -> wallet -> payouts -> first package. The current step gets one big
// button that opens the right tab and pulses the control (Jim: "it wasn't obvious", 2026-09-14)
function renderSteps(d) {
const card = $('gsCard'); if (!card) return;
const hasUser = !!d.username, hasWallet = !!d.address, hasPayouts = !!d.memberId, hasPackage = !!(d.memberId && (d.credits || 0) > 0);
const steps = [
{ k: 'user', t: 'Pick a username', done: hasUser },
{ k: 'wallet', t: 'Link your wallet', done: hasWallet },
{ k: 'payouts', t: 'Switch on payouts', done: hasPayouts },
{ k: 'package', t: 'Your first package', done: hasPackage }
];
if (steps.every(x => x.done)) { card.hidden = true; return; }
const cur = steps.find(x => !x.done);
let collapsed = false; try { collapsed = localStorage.getItem('iap.gs.collapsed') === '1'; } catch (e) {}
$('gsSub').innerHTML = steps.filter(x => x.done).length + ' of 4 done · <a href="#" id="gsToggle" style="color:var(--mint);text-decoration:none">' + (collapsed ? 'show' : 'hide') + '</a>';
$('gsToggle').addEventListener('click', e => { e.preventDefault(); try { localStorage.setItem('iap.gs.collapsed', collapsed ? '0' : '1'); } catch (er) {} renderSteps(d); });
$('gsSteps').hidden = collapsed; $('gsNow').hidden = collapsed;
$('gsSteps').innerHTML = steps.map((x, i) => '<div class="gs-step' + (x.done ? ' done' : x === cur ? ' now' : '') + '"><span class="n">' + (x.done ? '✓' : i + 1) + '</span><span>' + x.t + '</span></div>').join('');
const copy = {
user: ['Pick your username', 'It becomes your invite link and your public page, and it is permanent.', 'Choose a username', () => showOnboard(true)],
wallet: ['Link your wallet', 'Your payouts land in a wallet you control, so the site needs to know which one is yours. One free signature, no purchase. MetaMask recommended; Phantom users switch Polygon on first. Never held crypto? The wallet guide walks you through it.', 'Link my wallet', () => jumpTo('wallet', 'linkBtn')],
payouts: ['Switch on payouts', 'One small transaction registers your wallet with the contract so commissions can reach it. Buying any package does this automatically.', 'Activate payouts', () => jumpTo('wallet', 'activateBtn')],
package: ['Your first package', 'From $5. The $20 Activation package is the one that counts you as a qualifying buyer for your sponsor and unlocks adopting from the holding tank.', 'See packages', () => jumpTo('buy', null)]
}[cur.k];
$('gsNow').innerHTML = '<p><b>Next: ' + copy[0] + '</b>' + copy[1] + (cur.k === 'wallet' ? ' <a href="/wallets" target="_blank" rel="noopener" style="color:var(--mint)">Wallet guide</a>' : '') + '</p><button type="button" class="btn" id="gsGo">' + copy[2] + '</button>';
$('gsGo').addEventListener('click', copy[3]);
card.hidden = false;
}
function jumpTo(pane, id) {
setPane(pane);
setTimeout(() => { const el = id && $(id); if (!el) return; el.scrollIntoView({ behavior: 'smooth', block: 'center' }); el.classList.remove('pulse'); void el.offsetWidth; el.classList.add('pulse'); try { el.focus({ preventScroll: true }); } catch (e) {} }, 250);
}
async function loadDashboard() {
try {
loadNews(); loadLeaderboard();
const d = await (await fetch('/api/my/dashboard')).json();
if (d.error) return;
chatSync(d);
try { renderSteps(d); } catch (e) {}
MYID = d.memberId || MYID;
startLiveFeed();
if (!window.__lbChecked) { // daily login bonus, once per session (server guards once/day)
@@ -671,6 +704,7 @@
setPane(location.hash.slice(1) || 'overview');
$('campGate').hidden = !!me.memberId;
$('earnGate').hidden = !!me.memberId;
if (me.username && !me.address) { let shown = ''; try { shown = sessionStorage.getItem('iap.gs.walletHint'); sessionStorage.setItem('iap.gs.walletHint', '1'); } catch (e) {} if (shown !== '1') setTimeout(() => IAP.status('Next step when you are ready: link your wallet so your payouts have somewhere to land. The Getting started card at the top shows how.', 'ok'), 1200); }
loadDashboard();
const who = [];