Earn: video stops when leaving the tab/pane, 'all watched today' message, open earn tokens survive a redeploy; admin member search matches as you type, clearer old-site line; QA earn harness follows the done screen
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+22
-4
@@ -318,7 +318,7 @@
|
||||
}
|
||||
function kv(rows) { return '<table class="adm-table kv">' + rows.map(r => '<tr><th style="width:170px">' + r[0] + '</th><td>' + r[1] + '</td></tr>').join('') + '</table>'; }
|
||||
function renderMember(d) {
|
||||
mcCur = d; const a = d.account;
|
||||
mcCur = d; const a = d.account; $('memHits').hidden = true;
|
||||
$('memCard').hidden = false; document.querySelectorAll('#pane-members > .card').forEach(c => { if (c.id !== 'memCard' && c.id !== 'memSearchCard') c.hidden = true; });
|
||||
$('mcName').textContent = (a.username ? '@' + a.username : a.email) + (a.memberId ? ' · member #' + a.memberId : ' · free member');
|
||||
$('mcSub').textContent = 'joined ' + when(a.created) + ' · last seen ' + ago(a.lastSeen);
|
||||
@@ -342,7 +342,7 @@
|
||||
['Payouts received', t.payoutsIn + (t.payoutsIn ? ' · ' + polOf(t.receivedWei) + ' POL' : '')],
|
||||
['Credits', cr ? cr.available.toLocaleString() + ' available · ' + cr.inCampaigns.toLocaleString() + ' in campaigns · ' + cr.total.toLocaleString() + ' total' : '<span class="muted">-</span>'],
|
||||
['Earned pool', d.earnedSplit ? d.earnedSplit.total.toLocaleString() + ' (' + (d.earnedSplit.grade || 0).toLocaleString() + ' purchased-grade)' : '-'],
|
||||
['Legacy', d.legacy ? esc(d.legacy.brand) + ' ' + d.legacy.seg + (d.legacy.grant ? ' · ' + d.legacy.grant.credits + ' credits granted ' + when(d.legacy.grant.at) : ' · not granted') : '<span class="muted">not on the legacy list</span>'],
|
||||
['Old-site account', d.legacy ? 'had a ' + (d.legacy.brand === 'both' ? 'Faucet Wave and Tier One Ads' : d.legacy.brand === 'tier1ads' ? 'Tier One Ads' : 'Faucet Wave') + ' account (' + d.legacy.seg + ') · welcome-back credits ' + (d.legacy.grant ? d.legacy.grant.credits + ' issued ' + when(d.legacy.grant.at) : 'not issued (joined outside the legacy bridge)') : '<span class="muted">none on record</span>'],
|
||||
['Promo codes', d.promos.length ? d.promos.map(p => esc(p.code) + ' (' + p.credits + ', ' + when(p.ts) + ')').join('<br>') : '<span class="muted">none</span>'],
|
||||
['Drip', d.drip ? (d.drip.stopped ? 'stopped' : 'step ' + d.drip.step + ', next ' + when(d.drip.next_at)) + (d.drip.angle ? ' · ' + esc(d.drip.angle) : '') : '<span class="muted">-</span>'],
|
||||
['Holding tank', d.tank ? (d.tank.waiting ? '<b>waiting for a sponsor</b>' : 'not in tank') + (d.tank.adoptedBy.length ? ' · adopted by ' + d.tank.adoptedBy.map(x => memLink(x.email, x.name)).join(', ') : '') + (d.tank.adopted.length ? ' · adopted ' + d.tank.adopted.map(x => memLink(x.email, x.name)).join(', ') : '') : '-'],
|
||||
@@ -366,8 +366,26 @@
|
||||
if (location.hash !== '#members') history.replaceState(null, '', '#members');
|
||||
}
|
||||
function closeMember() { $('memCard').hidden = true; document.querySelectorAll('#pane-members > .card').forEach(c => { c.hidden = false; }); }
|
||||
$('memOpen').addEventListener('click', () => { const q = $('memSearch').value.trim(); if (q) openMember(q); });
|
||||
$('memSearch').addEventListener('keydown', e => { if (e.key === 'Enter') $('memOpen').click(); });
|
||||
// live matches while typing: any part of the username, email, member #, share code or wallet
|
||||
let memHitList = [];
|
||||
function memMatches(q) {
|
||||
q = q.toLowerCase();
|
||||
return allMembers.filter(a => [a.username, a.email, a.memberId ? '#' + a.memberId : '', a.memberId, a.code, a.address, a.sponsorName].filter(Boolean).join(' ').toLowerCase().includes(q)).slice(0, 12);
|
||||
}
|
||||
async function memTypeahead() {
|
||||
const q = $('memSearch').value.trim();
|
||||
if (!allMembers.length) { try { const r = await api('/api/admin/members'); allMembers = r.members || []; } catch (e) {} }
|
||||
if (q.length < 2) { $('memHits').hidden = true; memHitList = []; return; }
|
||||
memHitList = memMatches(q);
|
||||
$('memHits').innerHTML = memHitList.length ? memHitList.map(a => '<button type="button" data-mcopen="' + esc(a.email) + '" style="display:flex;gap:12px;width:100%;text-align:left;background:transparent;border:0;border-bottom:1px solid var(--line);padding:8px 12px;color:inherit;cursor:pointer;font:inherit"><b style="min-width:140px">' + (a.username ? '@' + esc(a.username) : '<span class="muted">no username</span>') + '</b><span>' + esc(a.email) + '</span><span class="muted">' + (a.memberId ? '#' + a.memberId : 'free') + (a.sponsorName ? ' · under ' + esc(a.sponsorName) : '') + '</span></button>').join('')
|
||||
: '<p class="muted small" style="margin:0;padding:8px 12px">No member matches that.</p>';
|
||||
$('memHits').hidden = false;
|
||||
}
|
||||
$('memSearch').addEventListener('input', memTypeahead);
|
||||
$('memSearch').addEventListener('focus', memTypeahead);
|
||||
$('memOpen').addEventListener('click', () => { const q = $('memSearch').value.trim(); if (!q) return; if (memHitList.length) openMember(memHitList[0].email); else openMember(q); });
|
||||
$('memSearch').addEventListener('keydown', e => { if (e.key === 'Enter') $('memOpen').click(); if (e.key === 'Escape') $('memHits').hidden = true; });
|
||||
document.addEventListener('click', e => { if (!e.target.closest('#memSearchCard')) $('memHits').hidden = true; });
|
||||
$('mcBack').addEventListener('click', closeMember);
|
||||
document.addEventListener('click', e => { const l = e.target.closest('[data-mcopen]'); if (l) { e.preventDefault(); openMember(l.dataset.mcopen); } });
|
||||
document.querySelectorAll('[data-mcact]').forEach(b => b.addEventListener('click', busy(b, async () => {
|
||||
|
||||
Reference in New Issue
Block a user