Leaderboard + referral contest: /leaderboard (week/month/all, read from chain, own positions excluded), Overview card with own rank, weekly and monthly winners recorded at rollover with credit ladders granted automatically and announced to Telegram

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-14 05:22:39 -05:00
parent b3523e9dc4
commit b0ef3b3a58
8 changed files with 181 additions and 7 deletions
+16 -1
View File
@@ -363,6 +363,7 @@
// site-wide activity (not about me): joins, tank, adoptions, purchases, payouts, qualifications
if (ev.type === 'Joined') { communityToast('👋 ' + ev.name + ' just joined' + (ev.tank ? ' and is waiting for a sponsor in the holding tank' : '')); liveRefresh(); return; }
if (ev.type === 'Adopted') { communityToast('🤝 ' + ev.sponsor + ' picked up ' + ev.member + ' from the holding tank'); liveRefresh(); return; }
if (ev.type === 'Contest') { communityToast('🏆 ' + ev.winner + ' won the ' + (ev.kind === 'week' ? 'weekly' : 'monthly') + ' referral contest'); return; }
if (ev.type === 'Badge') { communityToast('🏆 ' + ev.member + ' unlocked ' + ev.label); return; }
if (ev.type === 'Released') { communityToast('🪣 ' + ev.sponsor + ' returned ' + ev.member + ' to the holding tank'); liveRefresh(); return; }
const mine = MYID && (ev.recipientId === MYID || ev.toId === MYID || ev.sponsorId === MYID || ev.skippedId === MYID || ev.buyerId === MYID);
@@ -457,9 +458,23 @@
$('newsCard').addEventListener('click', () => { try { localStorage.setItem('iap.news.seen', r.latest || ''); } catch (e) {} $('newsList').querySelectorAll('span[style*="mint"]').forEach(s => { if (s.textContent === '●') s.remove(); }); }, { once: true });
} catch (e) {}
}
// Leaderboard card: top 5 this week + your own rank + the prize (Marty, 2026-09-14)
async function loadLeaderboard() {
if (!$('lbCard')) return;
try {
const r = await (await fetch('/api/leaderboard?period=week')).json();
const esc = t => String(t == null ? '' : t).replace(/[&<>"]/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]));
let h = r.prize ? '<p style="margin:0 0 8px"><b>Prize this week:</b> ' + esc(r.prize) + '</p>' : '';
h += r.top.length ? '<table style="width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums">' + r.top.slice(0, 5).map(x => '<tr><td style="padding:3px 0;width:26px;color:' + (x.rank === 1 ? '#ffd15c' : 'var(--muted)') + '">' + x.rank + '</td><td style="padding:3px 0"><b>' + esc(x.name) + '</b></td><td style="padding:3px 0;text-align:right">' + x.sales + ' sold · $' + x.usd + '</td></tr>').join('') + '</table>'
: '<p class="muted" style="margin:0">No packages sold yet this week. First sale takes the top spot.</p>';
h += r.me ? '<p style="margin:8px 0 0">You: <b>#' + r.me.rank + '</b> · ' + r.me.sales + ' sold · $' + r.me.usd + '</p>' : '<p class="muted" style="margin:8px 0 0">You: no sales yet this week. Sales are $20+ packages bought by people you sponsor.</p>';
h += '<p style="margin:6px 0 0"><a href="/leaderboard" target="_blank" rel="noopener" style="color:var(--mint)">Full leaderboard: week, month, all time →</a></p>';
$('lbList').innerHTML = h; $('lbCard').hidden = false;
} catch (e) {}
}
async function loadDashboard() {
try {
loadNews();
loadNews(); loadLeaderboard();
const d = await (await fetch('/api/my/dashboard')).json();
if (d.error) return;
chatSync(d);