← back to Commercialrealestate
Fix ?shortlist=sfv-pool (robust reload via native localStorage restore — verified 953 checked off); clean sfv-pool sub-header; clean Pool field value
bb5a372707082612a252ec0a99079775f70e8acf · 2026-08-26 09:52:53 -0700 · Steve Abrams
Files touched
M public/mls.htmlM public/sfv-pool.html
Diff
commit bb5a372707082612a252ec0a99079775f70e8acf
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Aug 26 09:52:53 2026 -0700
Fix ?shortlist=sfv-pool (robust reload via native localStorage restore — verified 953 checked off); clean sfv-pool sub-header; clean Pool field value
---
public/mls.html | 25 +++++++++++++++----------
public/sfv-pool.html | 10 +++++-----
2 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/public/mls.html b/public/mls.html
index d9aefb3..8a570d8 100644
--- a/public/mls.html
+++ b/public/mls.html
@@ -709,16 +709,21 @@ let _qT; $('#q').addEventListener('input',()=>{ clearTimeout(_qT); _qT=setTimeou
// deep-link ?shortlist=sfv-pool — land here with the SFV $700k-$1.2M set already CHECKED OFF (starred) +
// the Shortlist filter on, so the email / pool-page "open on CRCP" link shows exactly those listings here.
// Named preset (not ~950 ids in the URL): fetch the current id set from /api/sfv-pool and star them.
-(async function(){
- const preset=new URLSearchParams(location.search).get('shortlist'); if(preset!=='sfv-pool') return;
- try{
- const j=await (await fetch('/api/sfv-pool')).json();
- const ids=[...(j.withPool||[]),...(j.withoutPool||[]),...(j.unknown||[])].map(r=>r.id);
- ids.forEach(id=>SHORT.add(id)); saveShort();
- F.shortlist=true; if(typeof updateShortBtn==='function') updateShortBtn();
- const sc=$('#f_shortlist'); if(sc){ sc.checked=true; } // reflect the filter checkbox if present
- if(typeof render==='function') render();
- }catch(e){ console.warn('sfv-pool preset failed', e); }
+// deep-link ?shortlist=sfv-pool — robust: don't race boot()/hydrateFilters(). Instead write the shortlist
+// (cre_shortlist) + turn on the shortlist filter (mlsFilters.shortlist=1) into localStorage, then reload
+// to a CLEAN /mls.html so the page's OWN native restore path (SHORT built from cre_shortlist at parse +
+// hydrateFilters applying mlsFilters) shows exactly these listings — no timing race.
+(function(){
+ const sp=new URLSearchParams(location.search); if(sp.get('shortlist')!=='sfv-pool') return;
+ fetch('/api/sfv-pool').then(r=>r.json()).then(j=>{
+ const ids=[...(j.withPool||[]),...(j.withoutPool||[]),...(j.unknown||[])].map(r=>r.id).filter(Boolean);
+ if(!ids.length){ location.replace('/mls.html'); return; }
+ let cur=[]; try{ cur=JSON.parse(localStorage.getItem('cre_shortlist')||'[]'); }catch(e){}
+ localStorage.setItem('cre_shortlist', JSON.stringify([...new Set([...cur, ...ids])]));
+ let mf={}; try{ mf=JSON.parse(localStorage.getItem('mlsFilters')||'{}')||{}; }catch(e){}
+ mf.shortlist=1; localStorage.setItem('mlsFilters', JSON.stringify(mf));
+ location.replace('/mls.html'); // native restore path applies both on the clean reload
+ }).catch(e=>{ console.warn('sfv-pool preset failed', e); location.replace('/mls.html'); });
})();
function exportCSV(){ const rows=filtered(); const cols=visCols(); const cv=(r,c)=>{let v=cval(r,c); v=(v==null?'':String(v)); return '"'+v.replace(/"/g,'""')+'"';};
const csv=cols.map(c=>'"'+c.l+'"').join(',')+'\n'+rows.map(r=>cols.map(c=>cv(r,c)).join(',')).join('\n');
diff --git a/public/sfv-pool.html b/public/sfv-pool.html
index 3bf5d9e..06803a1 100644
--- a/public/sfv-pool.html
+++ b/public/sfv-pool.html
@@ -90,9 +90,9 @@
<body>
<div class="wrap">
<h1>🏊 San Fernando Valley Homes · $700k – $1.2M</h1>
- <div class="sub">Active single-family listings, split by swimming pool ·
- <a href="/mls.html?shortlist=sfv-pool">open these on CRCP (checked off) →</a> ·
- <a href="/mls.html">all LA listings →</a> · <span id="src"></span></div>
+ <div class="sub">Active single-family listings, split by swimming pool<br>
+ <a href="/mls.html?shortlist=sfv-pool">open these on CRCP (checked off) →</a> ·
+ <a href="/mls.html">all LA listings →</a></div>
<div class="stats" id="stats"></div>
@@ -184,7 +184,7 @@ function render() {
<div class="addr" data-field="Address">${r.address||'—'}</div>
<div class="price"><span data-field="Price">${money(r.price)}</span> <span data-field="$/sqft" style="font-size:12px;color:#8b949e;font-weight:400">${pp?'· '+pp:''}</span></div>
<div class="meta"><span data-field="City">${r.city}</span> · <span data-field="Beds">${r.beds||'?'}</span> bd / <span data-field="Baths">${r.baths||'?'}</span> ba · <span data-field="Sqft">${r.sqft?(+r.sqft).toLocaleString():'—'}</span> sqft${lot?' · lot <span data-field="Lot">'+lot+'</span>':''} · <span data-field="DOM">${r.days_on_market!=null?r.days_on_market+'d':''}</span></div>
- <div><span data-field="Pool">${poolBadge(r._pool)}</span></div>${feat}
+ <div><span data-field="Pool" class="badge ${r._pool==='true'?'pool':r._pool==='false'?'nopool':'pending'}">${r._pool==='true'?'🏊 Pool':r._pool==='false'?'No Pool':'Pending'}</span></div>${feat}
</div>`;
}).join('');
$('#foot').textContent = `${rows.length} shown · pool status enriched from Redfin listing detail (structured POOL_FEATURES). "Pending" = detail not yet checked or field absent.`;
@@ -214,7 +214,7 @@ async function load() {
const j = await r.json();
DATA = { withPool:j.withPool||[], withoutPool:j.withoutPool||[], unknown:j.unknown||[] };
allRows().forEach(x => byId.set(x.id, x));
- $('#src').textContent = 'source: ' + (j.source||'?');
+ const _src = $('#src'); if (_src) _src.textContent = 'source: ' + (j.source||'?');
// populate city dropdown
const cities = [...new Set(allRows().map(r=>r.city))].sort();
$('#city').insertAdjacentHTML('beforeend', cities.map(c=>`<option value="${c}">${c}</option>`).join(''));
← c87ea0c auto-data-snapshot: 2026-08-26T09:38:32 (3 data files) — dat
·
back to Commercialrealestate
·
sfv-pool map: Zillow-style price pins colored by pool + keyl 28b3bb2 →