[object Object]

← back to Commercialrealestate

mls: Just Listed + Just Sold quick-filter chips with adjustable day window (persisted)

fae32255b0d062ef045051acad89105cc6d80881 · 2026-07-07 07:11:49 -0700 · Steve Abrams

- 🆕 Just Listed = active & first_seen within N days; ✅ Just Sold = disposition sold & left market
  (off_market_at) within N days. Mutually exclusive; 'within N days' input (default 7, localStorage).
- created_at flows through /api/residential + mappers as first_seen.

Files touched

Diff

commit fae32255b0d062ef045051acad89105cc6d80881
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jul 7 07:11:49 2026 -0700

    mls: Just Listed + Just Sold quick-filter chips with adjustable day window (persisted)
    
    - 🆕 Just Listed = active & first_seen within N days; ✅ Just Sold = disposition sold & left market
      (off_market_at) within N days. Mutually exclusive; 'within N days' input (default 7, localStorage).
    - created_at flows through /api/residential + mappers as first_seen.
---
 public/mls.html  | 20 ++++++++++++++++----
 scripts/serve.js |  2 +-
 2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/public/mls.html b/public/mls.html
index fe26252..a191607 100644
--- a/public/mls.html
+++ b/public/mls.html
@@ -101,6 +101,7 @@
 <div class="shell">
 <aside class="rail">
   <div class="rsec"><h4>Asset class</h4><div class="chips" id="fType"></div>
+    <div style="margin-top:9px;display:flex;flex-wrap:wrap;gap:6px;align-items:center"><span class="chip" id="listedChip" style="border-color:rgba(63,185,80,.5);color:var(--acc)" title="Homes newly on the market within the day window">🆕 Just Listed</span><span class="chip" id="soldChip" style="border-color:rgba(88,166,255,.5);color:var(--blue)" title="Pulled listings matched to a recorded sale within the day window">✅ Just Sold</span><span style="display:inline-flex;align-items:center;gap:4px;font-size:11px;color:var(--mut)">within <input type="number" id="recentDays" min="1" max="365" step="1" style="width:52px;background:var(--card);color:var(--ink);border:1px solid var(--line);border-radius:7px;padding:4px 6px;font-size:12px" title="Day window for Just Listed / Just Sold"> days</span></div>
     <div style="margin-top:9px;display:flex;flex-wrap:wrap;gap:6px"><span class="chip" id="nqChip" data-warr="nonqm" style="border-color:rgba(188,140,255,.5);color:#bc8cff" title="Arcstone non-QM target: unwarrantable condos + small multifamily (1–9u) + mixed-use">◆ Non-QM</span><span class="chip" id="unwChip" data-warr="unwarrantable" style="border-color:rgba(248,81,73,.4);color:var(--bad)" title="Filter the table to non-FHA-approved condos (Arcstone non-QM target)">⚑ Unwarrantable condos</span><a class="navchip" href="/condos" title="Full condo drill-down page">condos page →</a></div></div>
   <div class="rsec"><h4>Status</h4><div class="chips" id="fStatus"></div></div>
   <div class="rsec"><h4>Submarket / city</h4><div class="chips" id="fCity"></div></div>
@@ -150,7 +151,9 @@ const COLS=[
   {k:'source',l:'Source',t:'link'},
 ];
 let DATA=[], view='table', sortKey='rank', sortDir=1, q='';
-const F={types:new Set(),cities:new Set(),status:new Set(),pmin:null,pmax:null,unwarrantable:false,nonqm:false,shortlist:false};
+const _rd=(function(){ const v=parseInt(localStorage.getItem('mlsRecentDays'),10); return (v>0&&v<=365)?v:7; })();
+const F={types:new Set(),cities:new Set(),status:new Set(),pmin:null,pmax:null,unwarrantable:false,nonqm:false,shortlist:false,justsold:false,justlisted:false,recentDays:_rd};
+const daysSince=d=>{ if(!d) return Infinity; const t=Date.parse(d); return isNaN(t)?Infinity:(Date.now()-t)/86400000; };
 // shared shortlist with the Explorer (same localStorage key + same listing ids)
 const SHORT=new Set((function(){ try{ return JSON.parse(localStorage.getItem('cre_shortlist')||'[]'); }catch(e){ return []; } })());
 function saveShort(){ try{ localStorage.setItem('cre_shortlist', JSON.stringify([...SHORT])); }catch(e){} }
@@ -219,8 +222,8 @@ function renderStats(rows){ const sb=$('#statsbar'); if(!sb) return; if(!rows.le
 // Listing lifecycle: status 'off_market' means it left Redfin's active feed (pulled). disposition
 // 'sold' (cross-referenced vs closed_sale) vs 'withdrawn'. Surfaced as Status = Active/Sold/Withdrawn.
 function lifeStatus(x){ return x.status==='off_market' ? (x.disposition==='sold'?'Sold':'Withdrawn') : 'Active'; }
-function mapCondo(c){ return { id:c.id, address:c.address, city:c.city, zip:c.zip, type:'Condo', price:+c.price||0, units:1, cap_rate:null, year_built:c.year_built||null, status:lifeStatus(c), off_date:c.off_market_at?String(c.off_market_at).slice(0,10):null, disposition:c.disposition||null, sold_price:c.sold_price?+c.sold_price:null, sold_date:c.sold_date?String(c.sold_date).slice(0,10):null, source:c.source, firm:c.firm_name||null, beds:c.beds, baths:c.baths, sqft:c.sqft, hoa:c.hoa, warrantable_status:c.warrantable_status, broker_name:c.broker_name, project_name:c.project_name }; }
-function mapSfr(s){ return { id:s.id, address:s.address, city:s.city, zip:s.zip, type:'Single-Family', price:+s.price||0, units:1, cap_rate:null, year_built:s.year_built||null, status:lifeStatus(s), off_date:s.off_market_at?String(s.off_market_at).slice(0,10):null, disposition:s.disposition||null, sold_price:s.sold_price?+s.sold_price:null, sold_date:s.sold_date?String(s.sold_date).slice(0,10):null, source:s.source, firm:s.firm_name||null, beds:s.beds, baths:s.baths, sqft:s.sqft, broker_name:s.broker_name||null }; }
+function mapCondo(c){ return { id:c.id, address:c.address, city:c.city, zip:c.zip, type:'Condo', price:+c.price||0, units:1, cap_rate:null, year_built:c.year_built||null, status:lifeStatus(c), first_seen:c.created_at||null, off_date:c.off_market_at?String(c.off_market_at).slice(0,10):null, disposition:c.disposition||null, sold_price:c.sold_price?+c.sold_price:null, sold_date:c.sold_date?String(c.sold_date).slice(0,10):null, source:c.source, firm:c.firm_name||null, beds:c.beds, baths:c.baths, sqft:c.sqft, hoa:c.hoa, warrantable_status:c.warrantable_status, broker_name:c.broker_name, project_name:c.project_name }; }
+function mapSfr(s){ return { id:s.id, address:s.address, city:s.city, zip:s.zip, type:'Single-Family', price:+s.price||0, units:1, cap_rate:null, year_built:s.year_built||null, status:lifeStatus(s), first_seen:s.created_at||null, off_date:s.off_market_at?String(s.off_market_at).slice(0,10):null, disposition:s.disposition||null, sold_price:s.sold_price?+s.sold_price:null, sold_date:s.sold_date?String(s.sold_date).slice(0,10):null, source:s.source, firm:s.firm_name||null, beds:s.beds, baths:s.baths, sqft:s.sqft, broker_name:s.broker_name||null }; }
 let VISCOL=(function(){let s={};try{s=JSON.parse(localStorage.getItem('mlsCols')||'{}');}catch(e){}return s;})();
 function colVis(k){ if(k in VISCOL) return !!VISCOL[k]; const c=COLS.find(x=>x.k===k); return c?c.def!==0:true; }
 function visCols(){ return COLS.filter(c=>colVis(c.k)); }
@@ -250,7 +253,7 @@ function isNonQM(r){ const t=(r.type||'').toLowerCase();
   if(r.type==='Condo' && r.warrantable_status && r.warrantable_status!=='fha_approved') return true;
   if(/multi/.test(t) && r.units>=1 && r.units<=9) return true;
   if(/mixed/.test(t)) return true; return false; }
-function anySelection(){ return F.types.size||F.cities.size||F.status.size||F.pmin!=null||F.pmax!=null||F.unwarrantable||F.nonqm||F.shortlist||(q&&q.length); }
+function anySelection(){ return F.types.size||F.cities.size||F.status.size||F.pmin!=null||F.pmax!=null||F.unwarrantable||F.nonqm||F.shortlist||F.justsold||F.justlisted||(q&&q.length); }
 function passFacets(r){
   if(F.types.size && !F.types.has(r.type)) return false;
   if(F.cities.size && !F.cities.has(r.city)) return false;
@@ -259,6 +262,10 @@ function passFacets(r){
   if(F.pmax!=null && !(+r.price<=F.pmax)) return false;
   if(F.unwarrantable && !(r.type==='Condo' && r.warrantable_status && r.warrantable_status!=='fha_approved')) return false;
   if(F.nonqm && !isNonQM(r)) return false;
+  if(F.justlisted && !(String(r.status||'').startsWith('Active') && daysSince(r.first_seen)<=F.recentDays)) return false;
+  // Just Sold = recently LEFT the market (off_market_at) with a matched sale — off-market date is the
+  // "just" event; sold_date is the closing date and can lag by weeks/months (escrow).
+  if(F.justsold && !(r.disposition==='sold' && daysSince(r.off_date)<=F.recentDays)) return false;
   if(F.shortlist && !SHORT.has(r.id)) return false;
   return true;
 }
@@ -346,6 +353,11 @@ const unwEl=document.getElementById('unwChip');
 if(unwEl) unwEl.addEventListener('click',()=>{ F.unwarrantable=!F.unwarrantable; unwEl.classList.toggle('active',F.unwarrantable); if(F.unwarrantable){ F.types=new Set(['Condo']); document.querySelectorAll('#fType .chip').forEach(x=>x.classList.toggle('active',x.dataset.ty==='Condo')); } render(); });
 const nqEl=document.getElementById('nqChip');
 if(nqEl) nqEl.addEventListener('click',()=>{ F.nonqm=!F.nonqm; nqEl.classList.toggle('active',F.nonqm); render(); });
+// Just Listed / Just Sold quick-filters + adjustable day window (persisted)
+const listedEl=document.getElementById('listedChip'), soldEl=document.getElementById('soldChip'), rdEl=document.getElementById('recentDays');
+if(rdEl){ rdEl.value=F.recentDays; rdEl.addEventListener('change',()=>{ const v=parseInt(rdEl.value,10); if(v>0&&v<=365){ F.recentDays=v; localStorage.setItem('mlsRecentDays',v); if(F.justsold||F.justlisted) render(); } }); }
+if(listedEl) listedEl.addEventListener('click',()=>{ F.justlisted=!F.justlisted; listedEl.classList.toggle('active',F.justlisted); if(F.justlisted){ F.justsold=false; soldEl&&soldEl.classList.remove('active'); } render(); });
+if(soldEl) soldEl.addEventListener('click',()=>{ F.justsold=!F.justsold; soldEl.classList.toggle('active',F.justsold); if(F.justsold){ F.justlisted=false; listedEl&&listedEl.classList.remove('active'); } render(); });
 // collapsible rail tabs — all collapsed on load
 const railEl=document.querySelector('.rail');
 if(railEl){ railEl.addEventListener('click',e=>{ const h=e.target.closest('h4'); if(h && h.parentElement.classList.contains('rsec')) h.parentElement.classList.toggle('collapsed'); });
diff --git a/scripts/serve.js b/scripts/serve.js
index d49306a..5ee330d 100644
--- a/scripts/serve.js
+++ b/scripts/serve.js
@@ -309,7 +309,7 @@ app.get('/api/residential', async (req, res) => {
       const r = await brokerdb.pool.query(
         `SELECT id, address, city, zip, price, beds, baths, sqft, year_built,
                 firm_name, broker_name, source, lat, lng,
-                status, off_market_at, disposition, sold_price, sold_date
+                status, off_market_at, disposition, sold_price, sold_date, created_at
            FROM sfr WHERE price > 0 AND (status='active' OR off_market_at > now() - interval '180 days')
           ORDER BY (status='active') DESC, created_at DESC, price DESC LIMIT $1`, [limit]);
       if (r.rows.length) return res.json({ sfr: r.rows, label: SFR_LABEL, source: 'db' });

← 018ff11 off-market: re-check withdrawn rows for later-recorded sales  ·  back to Commercialrealestate  ·  listings: real DAYS ON MARKET (gap-immune Just Listed) + In a31904e →