[object Object]

← 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 →