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:
@@ -637,8 +637,16 @@ function getOrgShare(rootId) {
|
||||
const orgPol = (rm.earnedPol || 0) + (root.downPol || 0);
|
||||
let generations = 0;
|
||||
(function depth(n, dep) { if (!n) return; if (dep > generations) generations = dep; depth(n.left, dep + 1); depth(n.right, dep + 1); })(root, 0);
|
||||
// members per generation below the root (gen 1 = the root's matrix children)
|
||||
const genCounts = [];
|
||||
{ let layer = [rootId]; const gseen = new Set([rootId]);
|
||||
while (layer.length && genCounts.length < 60) {
|
||||
const next = [];
|
||||
for (const nid of layer) { const mm = state.members[nid]; if (!mm) continue;
|
||||
for (const c of [mm.l, mm.r]) if (c && !gseen.has(c) && state.members[c]) { gseen.add(c); next.push(c); } }
|
||||
if (!next.length) break; genCounts.push(next.length); layer = next; } }
|
||||
return {
|
||||
...base, found: true, orgBelow, orgMembers, generations,
|
||||
...base, found: true, orgBelow, orgMembers, generations, genCounts,
|
||||
memberPct: +(100 * orgMembers / totalMembers).toFixed(1),
|
||||
belowPct: +(100 * orgBelow / totalMembers).toFixed(1),
|
||||
orgPol: +orgPol.toFixed(2),
|
||||
|
||||
+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){
|
||||
|
||||
@@ -41,7 +41,7 @@ FACTS:
|
||||
- SPILLOVER: when a sponsor's two matrix slots are full, the contract places new members in the next open slot further down (left to right) — possibly under someone else. Spillover fills that member's matrix and sets up future upgrade income to their position, but does NOT count toward qualification: only people who join using a member's own ID are their directs. Upgrade payments travel up the MATRIX (not who-referred-whom) and only stop at positions that are qualified (2 directs) AND already at the level being bought — otherwise the payment passes them by to the next eligible upline. Members can see their own matrix, spillover tags, and payments at https://rmcircle.team/my
|
||||
- PAY FLOW (full diagram at https://rmcircle.team/how-pay-works): TWO income streams. (1) Entry rewards — when a direct joins under a member's link, that member gets the entry reward (~326 POL at Premium) and keeps it, on EVERY direct (not just the first two). (2) Upgrade payments — each person below you pays you ONCE, at the single level matching how far below you they sit: someone 1 layer down pays you at their Ascensus upgrade, 2 layers down at Fabrica, 3 at Culmen, 4 at Apex, and so on. To catch each one you must be at that level yourself AND qualified — so stay one level ahead of your team's deepest active layer. This is why a member can be "skipped" on a payment: it was reserved for the position at the matching depth, or they weren't leveled up in time.
|
||||
- TIERS: Premium (the tier the whole team builds at, ${c.premiumEntryPol || 362} POL entry) pays and earns FULL amounts; Standard costs about half and pays/earns HALF at every level. A smaller-than-expected payment almost always came from a Standard-tier position below. Tier is fixed at registration and CANNOT be changed later (upgrading advances your LEVEL, not your tier). Always recommend joining Premium and having recruits do the same. Amount comparison at /how-pay-works.
|
||||
- MEMBER DASHBOARD & ALERTS: each member has a live dashboard at https://rmcircle.team/my (enter your ID) showing position, team, payments, pipeline (incoming money forming below), spillover tags, and qualification badges. Members can turn on opt-in EMAIL ALERTS there (notified when paid, and when they need to upgrade to catch incoming pay). A member's personal invite page to share is https://rmcircle.team/join/<their-id>.
|
||||
- MEMBER DASHBOARD & ALERTS: each member has a live dashboard at https://rmcircle.team/my (enter your ID) showing position, team, payments, pipeline (incoming money forming below), a team-depth summary (members per generation below you and which level's upgrade each generation pays you at), spillover tags, and qualification badges. Members can turn on opt-in EMAIL ALERTS there (notified when paid, and when they need to upgrade to catch incoming pay). A member's personal invite page to share is https://rmcircle.team/join/<their-id>.
|
||||
- RESILIENCE ("what if the creators disappear / owner loses keys / it falls apart over time"): the contract is autonomous and immutable — NO admin action, heartbeat, or living operator is required for joins, upgrades, matrix placement, or payouts; there is no pause switch and no expiry. Verified on-chain that the founder, development, and fee-receiver wallets are ordinary wallets (EOAs), NOT smart contracts — an ordinary wallet always accepts incoming POL even if its key is lost forever, so a dead or abandoned admin wallet cannot block any member payment (only the project's OWN uncollected fee would sit idle). The contract stores no balance (every payment is delivered in the same transaction). If the owner's key were lost, only the four limited admin powers freeze in place; members are unaffected. Details in section 6 of https://rmcircle.team/contract.
|
||||
- Current team sponsor: ${a ? `ID ${a.id}${c.showSponsorName && a.name ? ` (${a.name})` : ''}, ${a.directs}/2 directs` : 'shown on the start page'}. ${waiting} placement(s) waiting. Placements rotate as positions qualify — always verify on https://rmcircle.team/start right before joining.
|
||||
- Site pages: https://rmcircle.team/ (strategy overview + roadmap + live team stats), https://rmcircle.team/start (current sponsor + join steps), https://rmcircle.team/training (6 videos — team overview, wallet setup, funding, the new connect-wallet join flow on the site, the dApp backup method, how payments work — + spillover article), https://rmcircle.team/how-pay-works (the two income streams shown as a pay-flow diagram + Premium/Standard tier comparison), https://rmcircle.team/contract (plain-language security review of the verified smart contract — code can't change, no pooled funds, locked rules, honest list of operator powers), https://rmcircle.team/my (member dashboard), https://rmcircle.team/tools (for existing team members who want to promote — share-ready promo videos, copy-paste social posts, short/long email swipes, and a downloadable banner kit in every standard size; to write promos in their own voice, mybrandedvoice.com), https://rmcircle.team/disclaimer (affiliate/earnings/risk disclosures).
|
||||
|
||||
Reference in New Issue
Block a user