(function(){ const esc=s=>String(s??'').replace(/[&<>'"]/g,c=>({'&':'&','<':'<','>':'>',"'":''','"':'"'}[c])); const fmt=n=>Number(n||0).toLocaleString(undefined,{maximumFractionDigits:2}); const date=ts=>ts?new Date(ts*1000).toLocaleDateString(undefined,{year:'numeric',month:'short',day:'numeric'}):'—'; const prompt=document.getElementById('idPrompt'),dash=document.getElementById('dash'); function pathId(){const m=location.pathname.match(/^\/my\/(\d+)$/);if(m)return m[1];const q=new URLSearchParams(location.search).get('id');if(q&&/^\d+$/.test(q))return q;try{return localStorage.getItem('ctb.myId')||''}catch(e){return ''}} function card(n,focus){ if(!n)return '
open
slot
'; const badge=n.tier===2?'P':'S'; const qmark=n.directCount>=2?'✓':''; const down=n.downCount?`⬇ ${n.downCount} below · ${fmt(n.downPol)} POL`:'no downline yet'; return `
${qmark}${badge} #${n.id}${esc(n.levelName)}${n.directCount}/2 · ${fmt(n.earnedPol)} POL${down}
`; } function renderTree(root){ if(!root){document.getElementById('dTree').innerHTML='
Team view is still indexing — check back in a few minutes.
';return} const rows=[[root]]; for(let g=1;g<4;g++)rows.push(rows[g-1].flatMap(n=>n?[n.left||null,n.right||null]:[null,null])); if(!rows[3].some(Boolean))rows.pop(); document.getElementById('dTree').innerHTML=`
${rows.map((r,i)=>`
${r.map(n=>card(n,i===0&&n&&true)).join('')}
`).join('')}
`; } function render(d){ prompt.classList.add('hidden');dash.classList.remove('hidden'); document.getElementById('dTitle').textContent='#'+d.id; const qb=document.getElementById('dQualified'); if(qb)qb.outerHTML=d.directCount>=2 ?'★ Qualified' :`${2-d.directCount} more direct${2-d.directCount===1?'':'s'} to qualify`; document.getElementById('dFacts').innerHTML= `
Tier${esc(d.tierName)}
`+ `
Level${esc(d.levelName)}
`+ `
Directs${d.directCount}/2${d.directCount>=2?' ✓ qualified':''}
`+ `
Total received${fmt(d.totalEarnedPol)} POL
`+ `
Team below you${d.subtree?`${d.subtree.downCount} member${d.subtree.downCount===1?'':'s'}`:'—'}
`+ `
Member since${date(d.joinedAt)}
`; renderTree(d.subtree); const inc=d.income||[]; document.getElementById('dIncome').innerHTML=inc.length ?`
${inc.map(p=>``).join('')}
WhenFrom memberForAmount
${date(p.ts)}#${p.fromId}${esc(p.desc)}${fmt(p.pol)} POL
` :'
No payments yet — they appear here the moment they land on-chain.
'; document.getElementById('dLineage').innerHTML=d.uplineChain&&d.uplineChain.length ?`#${d.id} → ${d.uplineChain.map(i=>'#'+i).join(' → ')} (root)` :'You are at the top of your line.'; } async function load(id){ try{ const r=await fetch('/api/public/member?id='+id); const d=await r.json(); if(!r.ok)throw new Error(d.error||'Lookup failed'); if(!d.registered)throw new Error(`ID ${id} isn't registered on the smart contract — double-check the number.`); try{localStorage.setItem('ctb.myId',String(id))}catch(e){} if(!/^\/my\/\d+$/.test(location.pathname))history.replaceState(null,'','/my/'+id); render(d); }catch(x){ prompt.classList.remove('hidden');dash.classList.add('hidden'); document.getElementById('idError').textContent=x.message; } } document.getElementById('idForm').addEventListener('submit',e=>{ e.preventDefault(); const v=document.getElementById('memberId').value.trim(); if(!/^\d{1,15}$/.test(v)){document.getElementById('idError').textContent='Numbers only — the ID from the RM Circle dApp.';return} load(v); }); document.getElementById('switchId').addEventListener('click',()=>{ try{localStorage.removeItem('ctb.myId')}catch(e){} history.replaceState(null,'','/my'); dash.classList.add('hidden');prompt.classList.remove('hidden'); document.getElementById('memberId').value=''; }); const id=pathId(); if(id)load(id); })();