← 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
M public/admin/index.html
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 (>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 →