[object Object]

← back to Commercialrealestate

condos: surface FHA expiration date as a toggleable grid column

4edfac90e7ecb411c2b00ecb2673d493a49e9a44 · 2026-08-07 15:35:30 -0700 · Steve Abrams

Extract the matched FHA cert's expiration (MM/DD/YYYY) server-side from
warrant_source (listings) and expiration_date (FHA directory) and expose it as
fha_expiration_date on /api/condos and /api/fha-condos; add a default-off
'FHA expires' column in condos.html.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 4edfac90e7ecb411c2b00ecb2673d493a49e9a44
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Aug 7 15:35:30 2026 -0700

    condos: surface FHA expiration date as a toggleable grid column
    
    Extract the matched FHA cert's expiration (MM/DD/YYYY) server-side from
    warrant_source (listings) and expiration_date (FHA directory) and expose it as
    fha_expiration_date on /api/condos and /api/fha-condos; add a default-off
    'FHA expires' column in condos.html.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 public/condos.html |  4 ++++
 scripts/serve.js   | 15 ++++++++++++---
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/public/condos.html b/public/condos.html
index ae78101..8b3770d 100644
--- a/public/condos.html
+++ b/public/condos.html
@@ -212,6 +212,10 @@ function statusBadge(s){
 const FIELDS=[
   {k:'project_name',l:'Project',               col:1},
   {k:'warrantable_status', l:'Warrantability', badge:1, col:1},
+  // FHA-approval expiration (MM/DD/YYYY) — the date warrantability lapses / lapsed. Surfaced by the
+  // server from warrant_source (listings) or expiration_date (FHA directory). Plain string, not date:1
+  // (the value is date-only, so the datetime formatter would tack on a bogus "12:00 AM").
+  {k:'fha_expiration_date', l:'FHA expires', col:1},
   {k:'city',        l:'City',                  col:1},
   {k:'hoa',         l:'HOA/mo',       money:1, col:1, suf:'/mo'},
   {k:'beds',        l:'Beds',                  col:1},
diff --git a/scripts/serve.js b/scripts/serve.js
index 06062f1..671421a 100644
--- a/scripts/serve.js
+++ b/scripts/serve.js
@@ -712,6 +712,15 @@ function fhaEffectiveSignal(c, today) {
   return (exp < today) ? 'fha_expired' : 'fha_approved';
 }
 
+// Surface the matched FHA cert's expiration as a clean MM/DD/YYYY string so condos.html can show it
+// as a toggleable grid column. The date already rides inside warrant_source ("...exp MM/DD/YYYY" for
+// approved, "...Expired MM/DD/YYYY (expired)" for lapsed) on listings, and in expiration_date on the
+// raw FHA directory rows — both dirty. Extract the first MM/DD/YYYY, dropping any suffix. Read-only.
+function fhaExpiryOf(v) {
+  const m = String(v || '').match(/(\d{2})\/(\d{2})\/(\d{4})/);
+  return m ? m[0] : '';
+}
+
 // Normalize scrape placeholder strings ("N/A", "Unknown", "None", "TBD", "-") in an attribution
 // field to null, so a placeholder never renders as a real broker/firm (a clickable "N/A" drill-link)
 // or counts as a distinct firm in filters. Real values pass through untouched.
@@ -854,7 +863,7 @@ app.get('/api/condos', async (req, res) => {
            FROM condo_card ${where} ORDER BY (status='active') DESC, created_at DESC LIMIT 5000`, args);
       if (r.rows.length) {
         const today = new Date(); today.setHours(0, 0, 0, 0);
-        let rows = r.rows.map(c => overlayBroker({ ...c, warrantable_status: listingEffectiveWarrant(c, today), broker_name: cleanAttr(c.broker_name), firm_name: cleanAttr(c.firm_name) }));
+        let rows = r.rows.map(c => overlayBroker({ ...c, warrantable_status: listingEffectiveWarrant(c, today), fha_expiration_date: fhaExpiryOf(c.warrant_source || (c.warrant_signals && c.warrant_signals.source)), broker_name: cleanAttr(c.broker_name), firm_name: cleanAttr(c.firm_name) }));
         if (status && status !== 'all') rows = rows.filter(c => c.warrantable_status === status);
         return res.json({ condos: rows, label: CONDO_LABEL, source: 'db' });
       }
@@ -865,7 +874,7 @@ app.get('/api/condos', async (req, res) => {
     const file = path.join(ROOT, 'data', 'condos-redfin.json');
     const { condos = [] } = JSON.parse(fs.readFileSync(file, 'utf8'));
     const today = new Date(); today.setHours(0, 0, 0, 0);
-    let rows = condos.map(c => overlayBroker({ ...c, warrantable_status: listingEffectiveWarrant(c, today), broker_name: cleanAttr(c.broker_name), firm_name: cleanAttr(c.firm_name) }));
+    let rows = condos.map(c => overlayBroker({ ...c, warrantable_status: listingEffectiveWarrant(c, today), fha_expiration_date: fhaExpiryOf(c.warrant_source || (c.warrant_signals && c.warrant_signals.source)), broker_name: cleanAttr(c.broker_name), firm_name: cleanAttr(c.firm_name) }));
     if (status && status !== 'all') rows = rows.filter(c => c.warrantable_status === status);
     return res.json({ condos: rows, label: CONDO_LABEL, source: 'snapshot' });
   } catch (e) {
@@ -957,7 +966,7 @@ app.get('/api/fha-condos', (req, res) => {
     if (q) rows = rows.filter(c => (c.project_name + ' ' + c.city + ' ' + c.zip + ' ' + c.address).toLowerCase().includes(q));
     // Normalize the ALL-CAPS HUD city names + repair the "CANADA"/91011 truncation for display,
     // consistent with Panel 7 (fixCity, defined below). Non-mutating — the source JSON is untouched.
-    const out = rows.slice(0, 400).map(c => ({ ...c, city: fixCity(c.city, c.zip), warrant_signal: fhaEffectiveSignal(c, today) }));
+    const out = rows.slice(0, 400).map(c => ({ ...c, city: fixCity(c.city, c.zip), warrant_signal: fhaEffectiveSignal(c, today), fha_expiration_date: fhaExpiryOf(c.expiration_date) }));
     res.json({ label: meta.label, count: rows.length, condos: out });
   } catch (e) { res.status(502).json({ error: String(e.message).split('\n')[0], condos: [] }); }
 });

← c992532 CRCP: fleet-wide day/night toggle + legibility pass across a  ·  back to Commercialrealestate  ·  condos: add color-coded 'Days to expiry' field (live calc fr 41ae00f →