Member identity, promo tools, back-office color, seeded inventory
Real people, not numbers: usernames (unique, profile pane to set them), shown across the ledger, activity, rosters, and the sidebar chip; vanity invite links (/join/<username>) with late chain binding intact. Promo tools pane ships Branded Voice share posts and an email swipe personalized with each member's link. The earn viewer excludes a member's own campaigns, so nobody earns from their own spend. Back office gains the cyan/violet/amber accent family over the green base. Three house campaigns seeded so every surface shows live inventory. Assets v=20260905i. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+16
-11
@@ -52,10 +52,11 @@ window.IAP = (function () {
|
||||
const el = $('navWallet');
|
||||
if (!el) return;
|
||||
if (me.signedIn) {
|
||||
// email-only members have no wallet address yet
|
||||
const who = me.address
|
||||
? '<span class="mono">' + me.address.slice(0, 6) + '…' + me.address.slice(-4) + '</span>'
|
||||
: (me.email ? String(me.email).replace(/[&<>]/g, '') : 'signed in');
|
||||
// identity order: username, then email, then wallet
|
||||
const who = me.username
|
||||
? '<b>@' + String(me.username).replace(/[&<>]/g, '') + '</b>'
|
||||
: (me.email ? String(me.email).replace(/[&<>]/g, '')
|
||||
: (me.address ? '<span class="mono">' + me.address.slice(0, 6) + '…' + me.address.slice(-4) + '</span>' : 'signed in'));
|
||||
el.innerHTML = (me.memberId ? '<span class="badge">member #' + me.memberId + '</span> ' : '') + who;
|
||||
} else {
|
||||
el.innerHTML = '<a href="/my">Sign in</a>';
|
||||
@@ -65,17 +66,21 @@ window.IAP = (function () {
|
||||
}
|
||||
function describeEvent(ev, c) {
|
||||
const pol = w => fmtPol(w) + ' POL';
|
||||
// real people, not numbers: use usernames when the site knows them
|
||||
const nm = id => (ev.names && ev.names[id])
|
||||
? String(ev.names[id]).replace(/[&<>]/g, '')
|
||||
: 'member #' + id;
|
||||
switch (ev.type) {
|
||||
case 'Purchase': return '🧾 member #' + ev.buyerId + ' bought package #' + ev.productId
|
||||
case 'Purchase': return '🧾 ' + nm(ev.buyerId) + ' bought package #' + ev.productId
|
||||
+ ' (' + fmtUsd(ev.priceCents) + ') for ' + pol(ev.paidWei) + ' → +' + ev.creditAmount.toLocaleString() + ' credits';
|
||||
case 'TierPaid': return '💸 level ' + ev.tier + ' payout → member #' + ev.recipientId + ': ' + pol(ev.amountWei)
|
||||
case 'TierPaid': return '💸 level ' + ev.tier + ' payout → ' + nm(ev.recipientId) + ': ' + pol(ev.amountWei)
|
||||
+ (ev.hops ? ' (passed up ' + ev.hops + ')' : '');
|
||||
case 'PassedUp': return '↷ level ' + ev.tier + ' passed over #' + ev.skippedId + ' (' + ev.reason + ')';
|
||||
case 'PassedUp': return '↷ level ' + ev.tier + ' passed over ' + nm(ev.skippedId) + ' (' + ev.reason + ')';
|
||||
case 'AdminPaid': return '🏛 platform fee settled: ' + pol(ev.amountWei);
|
||||
case 'BuyerCounted': return '⭐ member #' + ev.sponsorId + ' now has ' + ev.newCount + ' qualifying buyer(s)';
|
||||
case 'MemberActivated': return '👤 member #' + ev.id + ' activated a payout wallet';
|
||||
case 'AwardPaid': return '🎁 award: ' + pol(ev.amountWei) + ' → member #' + ev.toId;
|
||||
case 'CreditsConsumed': return '📣 member #' + ev.memberId + ' ran ads: −' + ev.amount.toLocaleString() + ' credits';
|
||||
case 'BuyerCounted': return '⭐ ' + nm(ev.sponsorId) + ' now has ' + ev.newCount + ' qualifying buyer(s)';
|
||||
case 'MemberActivated': return '👤 ' + nm(ev.id) + ' activated a payout wallet';
|
||||
case 'AwardPaid': return '🎁 award: ' + pol(ev.amountWei) + ' → ' + nm(ev.toId);
|
||||
case 'CreditsConsumed': return '📣 ' + nm(ev.memberId) + ' ran ads: −' + ev.amount.toLocaleString() + ' credits';
|
||||
case 'PriceCached': return '🔮 oracle price refreshed';
|
||||
case 'FallbackPriceUsed': return '🔮 cached price bridged an oracle gap';
|
||||
default: return '· ' + ev.type;
|
||||
|
||||
Reference in New Issue
Block a user