Coaching Radar: separate Marty-owned positions (config.ownerIds) into their own action-item block, exclude from member-nudge tiers
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -98,12 +98,20 @@ async function loadCoaching(){
|
||||
if(!d.ready){out.innerHTML='<div class="empty">Chain snapshot not ready — try again in a minute.</div>';return}
|
||||
const nm=r=>r.name?`${esc(r.name)} (#${r.id})`:`#${r.id}`;
|
||||
const link=r=>`<a href="/my/${r.id}" target="_blank" rel="noopener" style="color:var(--teal)">${nm(r)}</a>`;
|
||||
const mineRisk=d.atRisk.filter(r=>r.owned),mineRoll=d.rollForward.filter(r=>r.owned);
|
||||
d.atRisk=d.atRisk.filter(r=>!r.owned);d.rollForward=d.rollForward.filter(r=>!r.owned);d.oneAway=d.oneAway.filter(r=>!r.owned);
|
||||
const mineHtml=(mineRisk.length||mineRoll.length)?
|
||||
`<h3 style="margin:12px 0 6px;font-size:14px">👑 Your positions — your own action items</h3>`+
|
||||
mineRisk.map(r=>`<div class="pp-row" style="padding:8px 12px;border-color:rgba(240,197,109,.4)"><div class="pp-icon">👑</div><div class="pp-body">${link(r)} — ${esc(r.levelName)}, <strong style="color:var(--gold)">${fmt(r.atRiskPol)} POL</strong> forming; needs <strong>${esc(r.neededLevelName||'qualification')}</strong> to catch it${r.earnedPol>=(r.upgradeCost||0)&&r.upgradeCost?' — <span style="color:var(--ok)">next step covered by its earnings</span>':r.upgradeCost?` (earned ${fmt(r.earnedPol)} vs ${fmt(r.upgradeCost)} next step)`:''}.</div></div>`).join('')+
|
||||
mineRoll.map(r=>`<div class="pp-row" style="padding:8px 12px;border-color:rgba(240,197,109,.4)"><div class="pp-icon">👑</div><div class="pp-body">${link(r)} — qualified at Scintilla, Ascensus (${fmt(r.ascensusCost)} POL) covered by its ${fmt(r.earnedPol)} POL earned, whenever you choose.</div></div>`).join('')
|
||||
:'';
|
||||
const t1=d.rollForward.map(r=>`<div class="pp-row" style="padding:8px 12px"><div class="pp-icon">💬</div><div class="pp-body">${link(r)} — qualified, still Scintilla, sitting on <strong>${fmt(r.earnedPol)} POL</strong> (Ascensus costs ${fmt(r.ascensusCost)}). One message: “your entry rewards already cover the upgrade that catches your team's first payments.”</div></div>`).join('')||'<div class="empty">Nobody stuck at qualified-Scintilla. 🎉</div>';
|
||||
const t2=d.atRisk.filter(r=>r.qualified&&r.level>1).map(r=>`<div class="pp-row" style="padding:8px 12px"><div class="pp-icon">⚠️</div><div class="pp-body">${link(r)} — ${esc(r.levelName)}, needs <strong>${esc(r.neededLevelName)}</strong> to catch <strong style="color:var(--gold)">${fmt(r.atRiskPol)} POL</strong> forming under them (from ${r.fromIds.map(f=>'#'+f).join(', ')}).</div></div>`).join('')||'<div class="empty">Everyone leveled is ahead of their wave. 🎉</div>';
|
||||
const t3=d.oneAway.map(r=>`<div class="pp-row" style="padding:8px 12px"><div class="pp-icon">🎯</div><div class="pp-body">${link(r)} — 1/2 directs, one placement from qualifying.</div></div>`).join('')||'<div class="empty">Nobody stranded at 1/2.</div>';
|
||||
const unq=d.atRisk.filter(r=>!r.qualified).map(r=>`<div class="pp-row" style="padding:8px 12px"><div class="pp-icon">⏰</div><div class="pp-body">${link(r)} — NOT qualified (${r.directCount}/2) with <strong style="color:var(--gold)">${fmt(r.atRiskPol)} POL</strong> already forming below. Qualification is urgent for them.</div></div>`).join('');
|
||||
out.innerHTML=
|
||||
`<div class="facts" style="grid-template-columns:repeat(4,1fr);margin-bottom:14px"><div class="fact"><small>Members scanned</small><strong>${d.scanned}</strong></div><div class="fact"><small>POL at risk</small><strong style="color:var(--gold)">${fmt(d.totals.atRiskPol)}</strong></div><div class="fact"><small>Easy wins</small><strong>${d.totals.rollForwardCount}</strong></div><div class="fact"><small>One direct away</small><strong>${d.totals.oneAwayCount}</strong></div></div>`+
|
||||
mineHtml+
|
||||
`<h3 style="margin:12px 0 6px;font-size:14px">Tier 1 · Easy wins — one message each</h3>${t1}`+
|
||||
`<h3 style="margin:16px 0 6px;font-size:14px">Tier 2 · Money at risk — coach the upgrade</h3>${t2}`+
|
||||
(unq?`<h3 style="margin:16px 0 6px;font-size:14px">Tier 2b · Money forming, not yet qualified</h3>${unq}`:'')+
|
||||
|
||||
@@ -516,7 +516,8 @@ async function handleApi(req,res,pathname){
|
||||
const names={};
|
||||
try{for(const s of getSponsors())names[String(s.id)]=s.name;}catch(e){}
|
||||
try{for(const s of readJson(SUBMISSIONS_FILE))if(s.newId&&!names[String(s.newId)])names[String(s.newId)]=s.memberName;}catch(e){}
|
||||
for(const list of [d.atRisk,d.rollForward,d.oneAway])for(const r of list)if(names[String(r.id)])r.name=names[String(r.id)];
|
||||
const ownedIds=new Set(parseOwnerIds());
|
||||
for(const list of [d.atRisk,d.rollForward,d.oneAway])for(const r of list){if(names[String(r.id)])r.name=names[String(r.id)];if(ownedIds.has(Number(r.id)))r.owned=true;}
|
||||
}
|
||||
return json(res,200,d);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user