Add "Copy plain-English summary" to the pipeline widget

Generates a chat-ready, per-member explainer of the upgrade/generation
payment structure — the recurring "will I miss upgrades?" question
answered from that member's real position: their spot, the one rule
(each layer pays you once at one level), their ladder with amounts and
which layers they're already eligible for, an honest "you miss it only
if you fall behind" note, and a calibrated next move (no false urgency —
distinguishes a layer that's close from one still climbing). One click
copies it for pasting into Telegram/chat; works for any member by ID.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-08-14 12:52:01 -05:00
parent a8c4b8e664
commit 77310f8974
+50
View File
@@ -152,7 +152,57 @@
}else html+='<p style="margin:0 0 8px;color:var(--muted)">Nobody is at their pay-you milestone yet — the members below are still climbing toward it.</p>'; }else html+='<p style="margin:0 0 8px;color:var(--muted)">Nobody is at their pay-you milestone yet — the members below are still climbing toward it.</p>';
if(building.length)html+=`<p class="micro" style="margin:10px 0 0">${building.length} more member${building.length===1?' is':'s are'} building toward their pay-you level${passedCount.n?`; ${passedCount.n} already passed theirs`:''}. Helping your leg upgrade IS your income.</p>`; if(building.length)html+=`<p class="micro" style="margin:10px 0 0">${building.length} more member${building.length===1?' is':'s are'} building toward their pay-you level${passedCount.n?`; ${passedCount.n} already passed theirs`:''}. Helping your leg upgrade IS your income.</p>`;
else if(passedCount.n)html+=`<p class="micro" style="margin:10px 0 0">${passedCount.n} member${passedCount.n===1?' has':'s have'} already passed their pay-you milestone.</p>`; else if(passedCount.n)html+=`<p class="micro" style="margin:10px 0 0">${passedCount.n} member${passedCount.n===1?' has':'s have'} already passed their pay-you milestone.</p>`;
html+=`<div style="margin-top:14px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><button id="dCopySummary" class="btn btn-secondary btn-sm">📋 Copy plain-English summary</button><span id="dCopyMsg" class="micro" style="margin:0"></span></div>`;
el.innerHTML=html; el.innerHTML=html;
const cs=document.getElementById('dCopySummary');
if(cs)cs.addEventListener('click',async()=>{
try{await navigator.clipboard.writeText(pipelineSummaryText(d));document.getElementById('dCopyMsg').textContent='Copied — paste it into your chat.';setTimeout(()=>{document.getElementById('dCopyMsg').textContent=''},4000);}catch(e){document.getElementById('dCopyMsg').textContent='Copy failed — long-press to select instead.'}
});
}
// Plain-English, chat-ready explainer of a member's upgrade pipeline — the
// "will I miss upgrades?" question answered from their real position.
function pipelineSummaryText(d){
const LV=LEVELS, up=(d.upgradeCosts&&d.upgradeCosts[d.tier===2?2:1])||[];
const money=n=>Math.round(n).toLocaleString();
const gens={};
(function walk(n,depth){if(!n||depth>8)return;if(depth>=1)(gens[depth]=gens[depth]||[]).push(n);walk(n.left,depth+1);walk(n.right,depth+1);})(d.subtree,0);
const myLevel=d.level||1, team=(d.subtree&&d.subtree.downCount)||0;
const L=[];
L.push(`RM Circle — your position #${d.id}, in plain English 👇`);
L.push('');
L.push(d.directCount>=2
? `✅ YOUR SPOT: ${d.tierName}, ${d.levelName} level, qualified (2/2 directs). ${team} ${team===1?'person':'people'} in your team so far.`
: `⚠️ YOUR SPOT: ${d.tierName}, ${d.levelName} level — NOT qualified yet (${d.directCount}/2 directs). Get ${2-d.directCount} more direct${2-d.directCount===1?'':'s'} of your own first — that's the ONE thing that unlocks everything below.`);
L.push('');
L.push(`HOW UPGRADES PAY YOU (the one rule that clears up all the confusion):`);
L.push(`Every layer of your team pays you ONCE, at ONE level. The people directly under you pay you when they upgrade to Ascensus. The next layer down pays you at Fabrica. The layer below that at Culmen. Each layer deeper pays you at the next level up the ladder.`);
L.push('');
L.push(`To CATCH each layer's payment, you only need to be that level yourself (and stay qualified). Your ladder right now:`);
const maxG=Math.min(6,Math.max(2,...Object.keys(gens).map(Number).concat([2])));
for(let g=1;g<=maxG;g++){
const amt=up[g-1]; if(!amt)continue;
const buys=LV[g]||'the top'; const need=LV[g-1];
const have=d.directCount>=2&&myLevel>=g;
const cnt=(gens[g]||[]).length;
L.push(`• Layer ${g}${cnt?` (${cnt} ${cnt===1?'person':'people'})`:''}: their ${buys} upgrade pays you ${money(amt)} POL each — needs you at ${need}${have?' ✅ you already are':' ← get here to catch it'}`);
}
L.push('');
L.push(`WILL YOU MISS THEM? Only if your team climbs past a level before you do. But nobody skips levels — they go up one at a time — so you always get warning. Stay one step ahead of your team's growth and you catch every single one. Fall behind and that one payment passes you to the next person up (it doesn't come back), so the whole game is simply: keep your level ahead of your deepest active layer.`);
L.push('');
// next concrete action
const myNext=up[myLevel-1];
const nextName=LV[myLevel]||'max level';
// shallowest layer you can't yet catch
let gap=0;
for(let g=1;g<=8;g++){ if((gens[g]||[]).length && !(d.directCount>=2&&myLevel>=g)){ gap=g; break; } }
// is anyone in the gap layer already close (at/near their pay-you level)?
const gapClose=gap&&(gens[gap]||[]).some(n=>(n.level||1)>=gap-1);
if(d.directCount<2) L.push(`YOUR NEXT MOVE: get your 2 directs. Until then none of this pipeline can pay you — spillover fills your team but only your own 2 qualify you.`);
else if(gap) L.push(`YOUR NEXT MOVE: your next uncovered layer is layer ${gap} — to catch their ${LV[gap]||'top'} upgrades you'll need to be at ${LV[gap-1]} (${myNext?money(myNext)+' POL':''}). They're still climbing toward it${gapClose?', and getting close — worth upgrading soon':", so no rush — just get there before they do"}. You're already eligible for everything shallower.`);
else if(myNext) L.push(`YOUR NEXT MOVE: you're currently eligible for every active layer. As your team goes deeper, upgrade to ${nextName} (${money(myNext)} POL) before that new layer climbs to its pay-you level.`);
L.push('');
L.push(`See it live and get a red alert the moment you'd miss one: rmcircle.saasy.top/my/${d.id}`);
return L.join('\n');
} }
function renderShare(d){ function renderShare(d){
const el=document.getElementById('dShare'); const el=document.getElementById('dShare');