[object Object]

← back to Prestige Car Wash

Admin: flag unworked leads going cold (>48h) on cards + funnel; fix undefined-status default

f74fd9f73d877ebbb1beaf6042b762de2d520659 · 2026-07-26 15:45:52 -0700 · steve@designerwallcoverings.com

Files touched

Diff

commit f74fd9f73d877ebbb1beaf6042b762de2d520659
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date:   Sun Jul 26 15:45:52 2026 -0700

    Admin: flag unworked leads going cold (>48h) on cards + funnel; fix undefined-status default
---
 public/admin/index.html | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/public/admin/index.html b/public/admin/index.html
index 79efa27..3549f12 100644
--- a/public/admin/index.html
+++ b/public/admin/index.html
@@ -191,7 +191,7 @@ const TABS=[
   {id:'google',label:'🟢 Google Business'},
   {id:'leads',label:'📨 Leads',api:'/api/admin/leads',search:['name','service','message','status'],
    card:l=>cardWrap(`<div class="row"><div class="cat">${enc(l.service||'general')}</div>
-       <span class="badge ${leadBadge(l.status)}">${enc(l.status||'new')}</span></div>
+       <span>${(l.status||'new')==='new'&&isCold(l.created_at)?'<span class="badge b-bad">⏳ cold</span> ':''}<span class="badge ${leadBadge(l.status)}">${enc(l.status||'new')}</span></span></div>
      <div class="ttl">${enc(l.name)}</div>
      <div class="kv"><span>Phone</span><span>${enc(l.phone)}</span></div>
      <div class="kv"><span>Email</span><span>${enc(l.email)}</span></div>
@@ -372,11 +372,13 @@ function render(){
 
 // Lead funnel roll-up (dtd:D 2026-07-26) — computed from /api/admin/leads (which carries
 // each lead's pipeline status), so the owner sees funnel health where they already look.
+// A "new" lead older than 48h is going cold — flag it so the owner works it first.
+function isCold(iso){ return !!iso && (Date.now()-new Date(iso).getTime())>48*36e5; }
 function leadFunnel(leads){
-  const st={new:0,contacted:0,booked:0,won:0,lost:0}; let week=0; const wk=Date.now()-7*864e5;
-  (leads||[]).forEach(l=>{ st[l.status]=(st[l.status]||0)+1; const t=l.created_at?new Date(l.created_at).getTime():0; if(t>=wk) week++; });
+  const st={new:0,contacted:0,booked:0,won:0,lost:0}; let week=0,cold=0; const wk=Date.now()-7*864e5;
+  (leads||[]).forEach(l=>{ const s=l.status||'new'; st[s]=(st[s]||0)+1; const t=l.created_at?new Date(l.created_at).getTime():0; if(t>=wk) week++; if(s==='new'&&isCold(l.created_at)) cold++; });
   const total=(leads||[]).length;
-  return {st,total,week,conv:total?Math.round((st.won/total)*100):0};
+  return {st,total,week,cold,conv:total?Math.round((st.won/total)*100):0};
 }
 function funnelCard(f){
   const cells=[['new','new · unworked'],['contacted','contacted'],['booked','booked'],['won','won'],['lost','lost']];
@@ -385,7 +387,7 @@ function funnelCard(f){
     <div class="stat">${cells.map(([k,lab])=>`<div class="s"><b>${f.st[k]}</b><span>${lab}</span></div>`).join('')}</div>
     <div class="kv"><span>New this week</span><b>${f.week}</b></div>
     <div class="kv"><span>Conversion (won / total)</span><b>${f.conv}%</b></div>
-    ${f.st.new>0?`<div class="blurb" style="color:var(--warn)">⚠️ ${f.st.new} new lead${f.st.new!==1?'s':''} waiting to be worked → <a href="#" onclick="go('leads');return false" style="color:var(--brand)">open Leads</a></div>`:'<div class="blurb b-mut" style="color:var(--mut)">No unworked leads — all caught up.</div>'}
+    ${f.st.new>0?`<div class="blurb" style="color:var(--warn)">⚠️ ${f.st.new} new lead${f.st.new!==1?'s':''} waiting${f.cold>0?` — <b style="color:var(--bad)">${f.cold} going cold (&gt;48h)</b>`:''} → <a href="#" onclick="go('leads');return false" style="color:var(--brand)">open Leads</a></div>`:'<div class="blurb" style="color:var(--mut)">No unworked leads — all caught up.</div>'}
   </div></div>`;
 }
 function renderOverview(){

← 53de6fd Admin Overview: lead-funnel summary (status counts, new-this  ·  back to Prestige Car Wash  ·  auto-save: 2026-07-26T16:14:26 (1 files) — server.js 1b0a067 →