← back to Rentv 2026
mockups/admin/A07.html
48 lines
<!doctype html><html lang="en"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>A07 · Firm Tree — RENTV Admin</title>
<link rel="stylesheet" href="../assets/base.css"><link rel="stylesheet" href="admin.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
body{background:#0d1014;color:#e7ecf1;font-family:'Inter',system-ui,sans-serif}
.wrap{max-width:1040px;margin:0 auto;padding:14px 20px}
.bar{margin:8px 0 14px}.bar input{width:100%;background:#11161c;border:1px solid #232a32;border-radius:9px;color:#e7ecf1;padding:11px 14px;font:inherit}
.firm{background:#11161c;border:1px solid #232a32;border-radius:11px;margin-bottom:9px;overflow:hidden}
.firm>.h{display:flex;align-items:center;gap:12px;padding:14px 16px;cursor:pointer}
.firm>.h:hover{background:#141b22}
.firm>.h .car{color:#8b939b;transition:transform .15s}.firm.open>.h .car{transform:rotate(90deg)}
.firm .nm{font-weight:800;font-size:15px;flex:1}.firm .ct{font-size:12px;color:#9aa4ad}
.firm .kids{display:none;border-top:1px solid #232a32;background:#0e141a}
.firm.open .kids{display:block}
.kid{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 16px 10px 40px;border-bottom:1px solid #171d24}
.kid .nm2{font-weight:600;font-size:13.5px}.kid .lic{font-size:11px;color:#37d67a;font-family:ui-monospace,monospace}
.firm .fa{padding:10px 16px 12px 40px}
</style></head>
<body>
<div class="admhead" data-eln><h1>RENTV Admin · <span>Firm Org Tree</span></h1><div class="fresh" id="fresh"></div></div>
<div class="wrap">
<div class="bar" data-eln><input id="q" placeholder="Search firms…"></div>
<div data-eln id="tree"></div>
</div>
<script src="../assets/chrome.js"></script><script src="admin-core.js"></script>
<script>
ADM.mount('A07', d=>{
const esc=ADM.esc;
// group brokers under their firm_name; list firms that have brokers, plus top firms
const byFirm={};d.brokers.forEach(b=>{const f=b.firm_name||'—';(byFirm[f]=byFirm[f]||[]).push(b);});
const firms=Object.keys(byFirm).sort((a,b)=>byFirm[b].length-byFirm[a].length);
document.getElementById('fresh').textContent=firms.length+' firms represented in the loaded broker set';
function render(){
const q=(document.getElementById('q').value||'').toLowerCase();
const list=firms.filter(f=>!q||f.toLowerCase().includes(q)||byFirm[f].some(b=>b.name.toLowerCase().includes(q)));
document.getElementById('tree').innerHTML=list.map(f=>{const kids=byFirm[f];const rec=d.firms.find(x=>x.name&&f&&x.name.toLowerCase()===f.toLowerCase());
return `<div class="firm"><div class="h"><span class="car">▶</span><span class="nm">${esc(f)}</span><span class="ct">${kids.length} broker${kids.length>1?'s':''}${rec?' · '+(rec.agent_count||0).toLocaleString()+' statewide':''}</span></div>
<div class="kids"><div class="fa"><div class="acts">${ADM.actions('firms',rec||{name:f,hq_city:kids[0].city,hq_state:kids[0].state_code})}</div></div>${
kids.map(b=>`<div class="kid"><div><div class="nm2">${esc(b.name)}</div><span class="lic">DRE ${esc(b.license_no||'')} · ${esc(b.city||'')}</span></div><div class="acts">${ADM.actions('brokers',b)}</div></div>`).join('')
}</div></div>`;}).join('');
document.querySelectorAll('.firm>.h').forEach(h=>h.onclick=()=>h.parentElement.classList.toggle('open'));
}
document.getElementById('q').oninput=render;render();
});
</script></body></html>