Team-depth breakdown: members per generation on admin org panel + member dashboard
- chain.js getOrgShare now returns genCounts (breadth-first members per generation below the root) - Admin "Your Organization vs. the Network" panel renders a Gen 1..N bar list with fill-vs-capacity (2^n slots) - Member dashboard "Your team" card gains a Team Depth section computed from the subtree client-side, labeling each generation with the level whose upgrade pays that position (gen D pays at the level D+1 buy) - AI chat system prompt updated to describe the new dashboard section Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+11
-1
@@ -73,9 +73,19 @@ async function loadOrgShare(){
|
||||
`</div>`+
|
||||
`<div class="progress-line" style="height:16px;margin:0 0 6px"><span style="width:${Math.min(100,d.memberPct)}%"></span></div>`+
|
||||
`<p style="color:var(--muted);margin:0 0 14px;font-size:14px">Your organization rooted at <strong class="mt-id">#${d.rootId}</strong> is <strong style="color:var(--text)">${d.orgMembers} of ${d.totalMembers}</strong> members in the whole contract (${d.orgBelow} below you + your position), and has earned <strong style="color:var(--text)">${fmt(d.orgPol)} of ${fmt(d.totalPol)} POL</strong> ever paid.</p>`+
|
||||
`<div class="facts" style="grid-template-columns:repeat(4,1fr)"><div class="fact"><small>Your org members</small><strong>${d.orgMembers}</strong></div><div class="fact"><small>Whole network</small><strong>${d.totalMembers}</strong></div><div class="fact"><small>Your org earned</small><strong>${fmt(d.orgPol)} POL</strong></div><div class="fact"><small>Network paid</small><strong>${fmt(d.totalPol)} POL</strong></div></div>`;
|
||||
`<div class="facts" style="grid-template-columns:repeat(4,1fr)"><div class="fact"><small>Your org members</small><strong>${d.orgMembers}</strong></div><div class="fact"><small>Whole network</small><strong>${d.totalMembers}</strong></div><div class="fact"><small>Your org earned</small><strong>${fmt(d.orgPol)} POL</strong></div><div class="fact"><small>Network paid</small><strong>${fmt(d.totalPol)} POL</strong></div></div>`+
|
||||
genBreakdownHtml(d.genCounts,d.rootId);
|
||||
}catch(x){out.innerHTML=`<div class="empty" style="color:var(--danger)">${esc(x.message)}</div>`}
|
||||
}
|
||||
function genBreakdownHtml(gc,rootId){
|
||||
if(!gc||!gc.length)return '';
|
||||
const rows=gc.map((c,i)=>{
|
||||
const cap=Math.pow(2,i+1), pctFill=Math.min(100,Math.round(100*c/cap));
|
||||
const capLabel=cap<=1024?` of ${cap} slots`:'';
|
||||
return `<div style="display:flex;align-items:center;gap:10px;margin:4px 0;font-size:13px"><span style="width:52px;color:var(--muted)">Gen ${i+1}</span><div class="progress-line" style="flex:1;height:10px"><span style="width:${pctFill}%"></span></div><span style="width:120px;text-align:right"><strong>${c}</strong><span style="color:var(--muted)">${capLabel}</span></span></div>`;
|
||||
}).join('');
|
||||
return `<div style="margin-top:16px"><small style="text-transform:uppercase;letter-spacing:.08em;color:var(--muted);font-size:11px">Depth — members per generation below #${rootId}</small><div style="margin-top:8px">${rows}</div></div>`;
|
||||
}
|
||||
document.getElementById('orgShareForm').addEventListener('submit',e=>{e.preventDefault();loadOrgShare()});
|
||||
let incomeAutoLoaded=false;
|
||||
async function loadIncome(){
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
<section id="tabDash" class="mp-panel">
|
||||
<div id="dFacts" class="facts" style="grid-template-columns:repeat(3,1fr);margin:18px 0"></div>
|
||||
<div id="dNextStep"></div>
|
||||
<div class="table-card" style="margin-bottom:18px"><div style="display:flex;justify-content:space-between;gap:12px;align-items:flex-start;flex-wrap:wrap"><div><h2 style="margin:0 0 4px">Your team</h2><p style="color:var(--muted);font-size:13px;margin:0 0 14px">Your position's matrix — the rollup line on each card counts everyone underneath, all the way down. Click a position to drill into that leg. Open slots are where the next placements land.</p></div><button id="dTreeToggle" class="btn btn-secondary btn-sm">List view</button></div><div id="dTreeNav" style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:12px"></div><div id="dTree"></div><p class="micro" style="margin:14px 0 0"><span class="mtp-qmark" style="position:static;display:inline-grid;vertical-align:middle">✓</span> qualified (2/2 directs) · <span class="mt-badge mt-prem">P</span> Premium · <span class="mt-badge">S</span> Standard · ⬇ everyone below that position (all generations) and the POL they've earned · <span style="color:var(--teal)">↧ spillover</span> = placed there by upline activity; only members who join with a position's own ID count toward its 2/2</p><div id="dSpillNote" class="hidden"></div></div>
|
||||
<div class="table-card" style="margin-bottom:18px"><div style="display:flex;justify-content:space-between;gap:12px;align-items:flex-start;flex-wrap:wrap"><div><h2 style="margin:0 0 4px">Your team</h2><p style="color:var(--muted);font-size:13px;margin:0 0 14px">Your position's matrix — the rollup line on each card counts everyone underneath, all the way down. Click a position to drill into that leg. Open slots are where the next placements land.</p></div><button id="dTreeToggle" class="btn btn-secondary btn-sm">List view</button></div><div id="dTreeNav" style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:12px"></div><div id="dTree"></div><div id="dGens" style="margin-top:14px"></div><p class="micro" style="margin:14px 0 0"><span class="mtp-qmark" style="position:static;display:inline-grid;vertical-align:middle">✓</span> qualified (2/2 directs) · <span class="mt-badge mt-prem">P</span> Premium · <span class="mt-badge">S</span> Standard · ⬇ everyone below that position (all generations) and the POL they've earned · <span style="color:var(--teal)">↧ spillover</span> = placed there by upline activity; only members who join with a position's own ID count toward its 2/2</p><div id="dSpillNote" class="hidden"></div></div>
|
||||
<div class="table-card" style="margin-bottom:18px;border-color:rgba(123,224,161,.4)"><h2 style="margin:0 0 4px">Your pipeline</h2><p style="color:var(--muted);font-size:13px;margin:0 0 12px">Money forming below you. Each generation in your leg pays your position at exactly one level — when a member's level catches up to their depth, their <em>next</em> upgrade comes to you.</p><div id="dPipeline"></div></div>
|
||||
<div class="table-card" style="margin-bottom:18px;border-color:rgba(78,214,203,.35)"><h2 style="margin:0 0 4px">Email me my alerts</h2><p style="color:var(--muted);font-size:13px;margin:0 0 12px">Get an email the moment this position is <strong>paid</strong>, and when it <strong>needs an upgrade</strong> to catch incoming pay — so you never miss one. Opt in with your email; unsubscribe anytime.</p><div id="dAlerts"></div></div>
|
||||
<div class="table-card" style="margin-bottom:18px"><h2 style="margin:0 0 4px">Share this position</h2><div id="dShare"></div><a class="btn btn-teal btn-sm" href="/tools" style="margin-top:14px">🎬 Promo Tools — posts, swipes, video clips & banners →</a></div>
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
?`<div class="table-wrap"><table class="table" style="min-width:520px"><thead><tr><th>When</th><th>From member</th><th>For</th><th>Amount</th></tr></thead><tbody>${inc.map(p=>`<tr><td>${date(p.ts)}</td><td>#${p.fromId}</td><td>${esc(p.desc)}</td><td><strong>${fmt(p.pol)} POL</strong></td></tr>`).join('')}</tbody></table></div>`
|
||||
:'<div class="empty">No payments yet — they appear here the moment they land on-chain.</div>';
|
||||
renderNextStep(d);
|
||||
renderGens(d);
|
||||
renderPipeline(d);
|
||||
renderAlerts(d);
|
||||
renderShare(d);
|
||||
@@ -136,6 +137,26 @@
|
||||
}catch(e){return ''}
|
||||
}
|
||||
const LEVELS=['Scintilla','Ascensus','Fabrica','Culmen','Apex','Fastigium','Vertex','Corona'];
|
||||
// Team depth — members per generation below this position, with the level
|
||||
// whose upgrade routes each generation's payment to this position (gen D
|
||||
// pays on the upgrade OUT of level D, i.e. buying level D+1).
|
||||
function renderGens(d){
|
||||
const el=document.getElementById('dGens');if(!el)return;
|
||||
const root=d.subtree;
|
||||
if(!root||(!root.left&&!root.right)){el.innerHTML='';return;}
|
||||
const gens=[];let layer=[root];
|
||||
while(layer.length&&gens.length<60){
|
||||
const next=[];
|
||||
layer.forEach(n=>{if(n.left)next.push(n.left);if(n.right)next.push(n.right);});
|
||||
if(!next.length)break;gens.push(next.length);layer=next;
|
||||
}
|
||||
const rows=gens.map((c,i)=>{
|
||||
const cap=Math.pow(2,i+1);
|
||||
const pays=i<7?`pays you at their <strong style="color:var(--text)">${LEVELS[i+1]}</strong> upgrade`:'beyond the 8 pay levels';
|
||||
return `<div style="display:flex;align-items:center;gap:10px;margin:5px 0;font-size:13px;flex-wrap:wrap"><span style="width:46px;color:var(--muted)">Gen ${i+1}</span><div class="progress-line" style="flex:1;min-width:90px;height:9px"><span style="width:${Math.min(100,Math.round(100*c/cap))}%"></span></div><span style="width:88px;text-align:right"><strong>${c}</strong><span style="color:var(--muted)">${cap<=1024?' of '+cap:''}</span></span><span class="micro" style="color:var(--muted);width:230px">${pays}</span></div>`;
|
||||
}).join('');
|
||||
el.innerHTML=`<div style="border-top:1px solid var(--line);padding-top:12px"><small style="text-transform:uppercase;letter-spacing:.08em;color:var(--muted);font-size:11px">Team depth — members per generation</small><div style="margin-top:8px">${rows}</div><p class="micro" style="margin:8px 0 0">Full generations duplicate: each one can hold twice the last. A generation pays this position at exactly one level — stay qualified and at that level to catch it.</p></div>`;
|
||||
}
|
||||
// "My Next Step" — the single clearest action + the level ladder + a funded
|
||||
// badge (server tells us funded true/false; it never sends the raw balance).
|
||||
function renderNextStep(d){
|
||||
|
||||
Reference in New Issue
Block a user