← back to Rentv
mockups/admin/A01.html
55 lines
<!doctype html><html lang="en"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>A01 · DataGrid — 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;font-size:13.5px}
.wrap{max-width:1300px;margin:0 auto;padding:14px 20px}
.bar{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:8px 0 12px}
.bar input{flex:1;min-width:240px;background:#11161c;border:1px solid #232a32;border-radius:9px;color:#e7ecf1;padding:10px 13px;font:inherit}
.bar select{background:#11161c;border:1px solid #232a32;border-radius:9px;color:#e7ecf1;padding:10px;font:inherit}
table{width:100%;border-collapse:collapse;background:#11161c;border:1px solid #232a32;border-radius:10px;overflow:hidden}
th{position:sticky;top:52px;background:#0e141a;text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:#8b939b;padding:11px 14px;border-bottom:1px solid #232a32;cursor:pointer}
td{padding:11px 14px;border-bottom:1px solid #171d24;vertical-align:top}
tr.r{cursor:pointer}tr.r:hover td{background:#141b22}
.nm{font-weight:700}.mono{font-family:ui-monospace,Menlo,monospace;color:#9aa4ad;font-size:12px}
tr.exp td{background:#0e141a;border-bottom:1px solid #232a32}
.expwrap{display:none}tr.open+tr.exp .expwrap{display:block}
.expwrap .kv{margin-top:10px}
</style></head>
<body>
<div class="admhead" data-eln><h1>RENTV Admin · <span>DataGrid</span></h1><div class="fresh" id="fresh"></div></div>
<div class="admtabs" data-eln id="tabs"><button data-tab="brokers" class="on">Brokers <span class="c" id="cB">0</span></button><button data-tab="firms">Firms <span class="c" id="cF">0</span></button><button data-tab="owners">Owners <span class="c" id="cO">0</span></button></div>
<div class="wrap">
<div class="bar" data-eln><input id="q" placeholder="Filter name, firm, city, license…"><select id="sort"><option value="name">Name A→Z</option><option value="firm">Firm</option><option value="city">City</option><option value="agents">Agents ↓</option></select><span style="color:#8b939b;font-size:12px" id="count"></span></div>
<table data-eln><thead id="thead"></thead><tbody id="tbody"></tbody></table>
</div>
<script src="../assets/chrome.js"></script><script src="admin-core.js"></script>
<script>
let S={tab:'brokers'};
ADM.mount('A01', d=>{
S.d=d; document.getElementById('cB').textContent=d.totalB.toLocaleString();document.getElementById('cF').textContent=d.totalF.toLocaleString();document.getElementById('cO').textContent=d.owners.length;
document.getElementById('fresh').textContent='CA DRE registry · '+d.brokers.length+' brokers loaded of '+d.totalB.toLocaleString()+' statewide';
const esc=ADM.esc;
const cols={brokers:['Broker','Firm','City','License','Status'],firms:['Firm','HQ','Agents','License'],owners:['Address','Type','Assessed','Recorded']};
function rows(){let r=(S.tab==='brokers'?d.brokers:S.tab==='firms'?d.firms:d.owners).slice();const q=(document.getElementById('q').value||'').toLowerCase();if(q)r=r.filter(x=>JSON.stringify(x).toLowerCase().includes(q));const s=document.getElementById('sort').value;const k={name:'name',firm:S.tab==='brokers'?'firm_name':'name',city:S.tab==='firms'?'hq_city':'city',agents:'agent_count'}[s];r.sort((a,b)=>s==='agents'?(b.agent_count||0)-(a.agent_count||0):String(a[k]||a.name||a.address||'').localeCompare(String(b[k]||b.name||b.address||'')));return r;}
function render(){
document.getElementById('thead').innerHTML='<tr>'+cols[S.tab].map(c=>`<th>${c}</th>`).join('')+'</tr>';
const r=rows();
document.getElementById('tbody').innerHTML=r.map((x,i)=>{
let cells;
if(S.tab==='brokers')cells=`<td class="nm">${esc(x.name)}</td><td><a class="field-link" href="${ADM.LI_C(x.firm_name||'')}" target="_blank" onclick="event.stopPropagation()">${esc(x.firm_name||'—')}</a></td><td>${esc(x.city||'—')}</td><td class="mono"><a class="field-link" href="${ADM.DRE(x.license_no||'')}" target="_blank" onclick="event.stopPropagation()">${esc(x.license_no||'—')}</a></td><td>${esc(x.license_status||'—')}</td>`;
else if(S.tab==='firms')cells=`<td class="nm">${esc(x.name)}</td><td>${esc(ADM.loc(x)||'—')}</td><td><b>${(x.agent_count||0).toLocaleString()}</b></td><td class="mono">${esc(x.license_no||'—')}</td>`;
else cells=`<td class="nm">${esc(x.address||x.ain)}</td><td>${esc(x.type_label||'')}</td><td><b>${RENTV.shortUsd(x.assessed_total)}</b></td><td>${RENTV.dstr(x.recording_date)}</td>`;
return `<tr class="r" data-i="${i}">${cells}</tr><tr class="exp"><td colspan="${cols[S.tab].length}"><div class="expwrap"><div class="acts">${ADM.actions(S.tab,x)}</div></div></td></tr>`;
}).join('');
document.getElementById('count').textContent=r.length+' shown';
document.querySelectorAll('tr.r').forEach(tr=>tr.onclick=()=>tr.classList.toggle('open'));
}
document.getElementById('tabs').onclick=e=>{const b=e.target.closest('button');if(!b)return;document.querySelectorAll('#tabs button').forEach(x=>x.classList.remove('on'));b.classList.add('on');S.tab=b.dataset.tab;render();};
document.getElementById('q').oninput=render;document.getElementById('sort').onchange=render;
render();
});
</script></body></html>