← back to Rentv V1
Desk search now queries the full CA registry live (debounced /api/brokers?q= + /api/firms?q=) instead of filtering the loaded 500
eb6fd3d562e019b8fa7eb00a7959b0e6d4df74eb · 2026-07-22 18:18:49 -0700 · Steve
Files touched
Diff
commit eb6fd3d562e019b8fa7eb00a7959b0e6d4df74eb
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Jul 22 18:18:49 2026 -0700
Desk search now queries the full CA registry live (debounced /api/brokers?q= + /api/firms?q=) instead of filtering the loaded 500
---
public/desk.html | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/public/desk.html b/public/desk.html
index 479bbb3..b8bdc66 100644
--- a/public/desk.html
+++ b/public/desk.html
@@ -121,6 +121,18 @@ async function jget(u,fb){try{const r=await fetch(u,{credentials:'same-origin'})
renderAll();
})();
function scopeData(){return D.scope==='brokers'?D.brokers:D.scope==='firms'?D.firms:D.owners;}
+const debounce=(fn,ms)=>{let t;return(...a)=>{clearTimeout(t);t=setTimeout(()=>fn(...a),ms);};};
+// live server-side search across the FULL registry (382k brokers / 34k firms) via the proxy;
+// owners are only 12 so they filter client-side; empty term returns the loaded set.
+async function liveRows(scope,term){
+ term=(term||'').trim();
+ if(!term) return scopeData();
+ if(scope==='owners') return D.owners.filter(x=>JSON.stringify(x).toLowerCase().includes(term.toLowerCase()));
+ const ep=scope==='firms'?'/api/firms':'/api/brokers';
+ const v=await jget(ep+'?state=CA&q='+encodeURIComponent(term)+'&limit=100',null);
+ if(v&&v.rows&&v.rows.length) return v.rows;
+ return scopeData().filter(x=>JSON.stringify(x).toLowerCase().includes(term.toLowerCase()));
+}
// rail
$('rail').addEventListener('click',e=>{const btn=e.target.closest('button');if(!btn)return;
if(btn.dataset.v){document.querySelectorAll('#rail [data-v]').forEach(x=>x.classList.remove('on'));btn.classList.add('on');D.view=btn.dataset.v;document.querySelectorAll('.view').forEach(v=>v.classList.remove('on'));$('v-'+D.view).classList.add('on');}
@@ -136,9 +148,9 @@ function directory(){
function detail(x){if(!x){$('ddetail').innerHTML='';return;}
const grid=D.scope==='owners'?[['Assessed',shortUsd(x.assessed_total)],['SqFt',(x.sqft||0).toLocaleString()],['Built',x.year_built||'—'],['AIN',x.ain]]:D.scope==='firms'?[['Agents',(x.agent_count||0).toLocaleString()],['HQ',loc(x)||'—'],['License',x.license_no||'—'],['Source',x.source||'—']]:[['License',x.license_no||'—'],['Type',x.license_type||'—'],['Firm',x.firm_name||'—'],['City',x.city||'—']];
$('ddetail').innerHTML=`<div class="k">${esc(D.scope==='owners'?(x.type_label||'Asset'):D.scope==='firms'?'Brokerage':(x.license_type||'Licensee'))}</div><h2>${esc(nm(x))}</h2><div class="meta">${esc(D.scope==='owners'?[x.address,x.city].filter(Boolean).join(', '):(sub(D.scope,x)+' · '+(loc(x)||'')))}</div><div class="acts">${actions(D.scope,x)}</div><div class="grid">${grid.map(([k,v])=>`<div class="cell"><div class="kk">${k}</div><div class="vv">${esc(v)}</div></div>`).join('')}</div>`;}
- function draw(){const r=list();$('drows').innerHTML=r.map((x,i)=>`<div class="row${i===D.selDir?' sel':''}" data-i="${i}"><div class="nm">${esc(nm(x))}</div><div class="f">${esc(sub(D.scope,x))}</div></div>`).join('');
+ async function draw(){const r=await liveRows(D.scope,$('dq').value);$('drows').innerHTML=r.map((x,i)=>`<div class="row${i===D.selDir?' sel':''}" data-i="${i}"><div class="nm">${esc(nm(x))}</div><div class="f">${esc(sub(D.scope,x))}</div></div>`).join('')||'<div class="fresh">No matches in the registry.</div>';
$('drows').querySelectorAll('.row').forEach(row=>row.onclick=()=>{D.selDir=+row.dataset.i;$('drows').querySelectorAll('.row').forEach(x=>x.classList.remove('sel'));row.classList.add('sel');detail(r[D.selDir]);});detail(r[D.selDir]||r[0]);}
- $('dq').oninput=()=>{D.selDir=0;draw();};draw();
+ $('dq').oninput=debounce(()=>{D.selDir=0;draw();},300);draw();
}
// ── Map ──
function map(){
@@ -161,10 +173,10 @@ function analytics(){
// ── Command ──
function command(){
$('v-command').innerHTML=`<div class="cmd"><div class="box"><div class="in"><span style="color:#8b939b;font-size:18px">⌘</span><input id="cq" placeholder="Search ${D.scope}…"></div><div class="results" id="cres"></div></div></div>`;
- function draw(){let r=scopeData().slice();const v=($('cq').value||'').toLowerCase();if(v)r=r.filter(x=>JSON.stringify(x).toLowerCase().includes(v));r=r.slice(0,40);
+ async function draw(){let r=(await liveRows(D.scope,$('cq').value)).slice(0,40);
$('cres').innerHTML=r.map((x,i)=>`<div class="res${i===0?' hot':''}"><div class="nm">${esc(nm(x))}</div><div class="f">${esc(sub(D.scope,x))}${loc(x)?' · '+esc(loc(x)):''}</div><div class="exp"><div class="acts">${actions(D.scope,x)}</div></div></div>`).join('')||'<div class="res"><div class="f">No matches.</div></div>';
$('cres').querySelectorAll('.res').forEach(el=>el.onclick=e=>{if(e.target.closest('a'))return;el.classList.toggle('open');});}
- $('cq').oninput=draw;draw();
+ $('cq').oninput=debounce(draw,300);draw();
}
</script>
</body></html>
← a832ec3 auto-save: 2026-07-22T18:15:55 (3 files) — data/markets.json
·
back to Rentv V1
·
Link the Broker & Owner Intelligence Desk from the homepage e6efe83 →