From 25eddf19c44e55426febb4631399243ba45c35b1 Mon Sep 17 00:00:00 2001 From: martbost Date: Mon, 31 Aug 2026 05:18:10 -0500 Subject: [PATCH] Dashboard: show what an upgrade buys, not just what it costs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upgrade panel showed a price, a funded badge and a button. Nothing on it said what the member would get. 53 of 87 qualified members in the org are parked at Ascensus, and a panel that reads as a bill is part of why. It now leads with what the rung unlocks, in the member's own numbers: the generation it extends reach to, how many people they already have sitting there, and what each of those pays when they climb. genCounts already existed in getOrgShare; this just points it at the member instead of at the admin. The line that matters most is arithmetic, not persuasion: because every rung costs exactly twice the last, the first catch at the new level is exactly double what the upgrade cost. That is Lesson 8's whole argument, and the panel now makes it where the decision is actually taken rather than leaving it in a lesson nobody opens at the right moment. Wrapped in try/catch — if the org walk fails the panel renders as before. Co-Authored-By: Claude Fable 5 --- public/my.js | 19 +++++++++++++++++++ server.js | 13 +++++++++++++ 2 files changed, 32 insertions(+) diff --git a/public/my.js b/public/my.js index 34c91f5..963fb27 100644 --- a/public/my.js +++ b/public/my.js @@ -192,8 +192,27 @@ const ns=d.nextStep||{}; if(ns.kind!=='upgrade'||d.directCount<2){el.innerHTML='';return;} const name=LEVELS[ns.nextLevel-1]||('Level '+ns.nextLevel); + // What this rung buys, in their own numbers. A price with no reason attached + // is just a bill — this is the reason. + const op=ns.opens||{}; + let why=''; + if(op.perCatch>0){ + const gname=LEVELS[op.gen]||('Level '+(op.gen+1)); + const have=(op.genSize!=null&&op.genSize>0) + ? `You already have ${op.genSize} ${op.genSize===1?'person':'people'} there.` + : `That generation is still filling.`; + why=`
+ What this unlocks: ${esc(name)} extends your reach to + generation ${op.gen}. ${have} + Each of them pays you ${fmt(op.perCatch)} POL when they buy ${esc(gname)}. +
Your first catch at this level is ${fmt(op.perCatch)} POL — + exactly double what this upgrade costs, because every rung is twice the last. + That is the whole idea behind Lesson 8 — time your upgrades to your catches.
+
`; + } el.innerHTML=`

⬆️ Upgrade to ${esc(name)} — right from this page

+ ${why}

Exact cost ${fmt(ns.cost)} POL, read live from the contract. Connect the wallet that owns position #${d.id}, confirm once, done. ${ns.funded?'Your wallet already covers it ✓':'Your wallet does not cover it yet — you can time it to your next catches, or top up below.'}

${ns.funded?'':``} diff --git a/server.js b/server.js index ca02d1d..eee0b65 100644 --- a/server.js +++ b/server.js @@ -590,6 +590,19 @@ async function handleApi(req,res,pathname){ let funded=null; try{ if(r.account&&cost){ const bal=await chain.balanceOf(r.account); if(bal!=null) funded=bal>=cost; } }catch(e){} r.nextStep={kind:'upgrade',nextLevel:lvl+1,cost,funded}; + // What the upgrade actually BUYS. The panel used to show a price with no + // reason attached, which is how 53 qualified members read it and closed + // the tab. Owning level L catches generation L, so this rung opens the + // generation numbered nextLevel — and because upgrade costs double every + // rung, the first catch there is exactly twice what this rung costs. + try{ + const opensGen=lvl+1; + const perCatch=(r.upgradeCosts&&r.upgradeCosts[tier]&&r.upgradeCosts[tier][lvl])||0; + const share=chain.getOrgShare(id); + const genSize=(share&&share.ready&&share.found&&Array.isArray(share.genCounts)) + ? (share.genCounts[opensGen-1]||0) : null; + r.nextStep.opens={gen:opensGen,perCatch,genSize}; + }catch(e){} }else{ r.nextStep={kind:'max'}; }