← back to Marketing Command Center
clients panel: coverage summary (contacts/emails/IG/LinkedIn across all groups); manifest carries per-group counts
57231265b62a785c55d8f488d9be8dd7be9ab123 · 2026-07-16 12:00:40 -0700 · steve
Files touched
M public/data/clients-manifest.jsonM public/panels/clients.htmlM public/panels/clients.jsM scripts/build-clients-manifest.js
Diff
commit 57231265b62a785c55d8f488d9be8dd7be9ab123
Author: steve <steve@designerwallcoverings.com>
Date: Thu Jul 16 12:00:40 2026 -0700
clients panel: coverage summary (contacts/emails/IG/LinkedIn across all groups); manifest carries per-group counts
---
public/data/clients-manifest.json | 35 ++++++++++++++++++++++++++++-------
public/panels/clients.html | 1 +
public/panels/clients.js | 7 +++++++
scripts/build-clients-manifest.js | 5 +++--
4 files changed, 39 insertions(+), 9 deletions(-)
diff --git a/public/data/clients-manifest.json b/public/data/clients-manifest.json
index cc2243f..0494bc4 100644
--- a/public/data/clients-manifest.json
+++ b/public/data/clients-manifest.json
@@ -6,49 +6,70 @@
"label": "FileMaker Clients",
"file": "clients-fm.json",
"kind": "clients",
- "count": 43234
+ "count": 43234,
+ "with_email": 36506,
+ "with_instagram": 0,
+ "with_linkedin": 0
},
{
"id": "la-arch-interior-design",
"label": "La Arch Interior Design",
"file": "prospects-la-arch-interior-design.json",
"kind": "prospects",
- "count": 1727
+ "count": 1727,
+ "with_email": 1257,
+ "with_instagram": 991,
+ "with_linkedin": 285
},
{
"id": "la-architects",
"label": "La Architects",
"file": "prospects-la-architects.json",
"kind": "prospects",
- "count": 1724
+ "count": 1724,
+ "with_email": 1298,
+ "with_instagram": 919,
+ "with_linkedin": 435
},
{
"id": "nyc-architects",
"label": "Nyc Architects",
"file": "prospects-nyc-architects.json",
"kind": "prospects",
- "count": 1024
+ "count": 1024,
+ "with_email": 707,
+ "with_instagram": 0,
+ "with_linkedin": 0
},
{
"id": "places-batch-1",
"label": "Places Batch 1",
"file": "prospects-places-batch-1.json",
"kind": "prospects",
- "count": 263
+ "count": 263,
+ "with_email": 196,
+ "with_instagram": 0,
+ "with_linkedin": 0
},
{
"id": "santa-barbara",
"label": "Santa Barbara",
"file": "prospects-santa-barbara.json",
"kind": "prospects",
- "count": 170
+ "count": 170,
+ "with_email": 115,
+ "with_instagram": 0,
+ "with_linkedin": 0
},
{
"id": "sf-architects",
"label": "Sf Architects",
"file": "prospects-sf-architects.json",
"kind": "prospects",
- "count": 1033
+ "count": 1033,
+ "with_email": 690,
+ "with_instagram": 0,
+ "with_linkedin": 0
}
]
}
\ No newline at end of file
diff --git a/public/panels/clients.html b/public/panels/clients.html
index 1bc6cb0..f7dc591 100644
--- a/public/panels/clients.html
+++ b/public/panels/clients.html
@@ -15,6 +15,7 @@
<span class="muted" id="cl-note" style="font-size:11.5px;">Staged locally — not uploaded to Constant Contact.</span>
</div>
<div id="cl-tabs" class="row" style="gap:6px;margin-top:12px;flex-wrap:wrap;"></div>
+ <div id="cl-coverage" class="muted" style="font-size:11.5px;margin-top:10px;"></div>
</div>
<div class="card" id="cl-controls" hidden>
diff --git a/public/panels/clients.js b/public/panels/clients.js
index 272b21a..4b443f9 100644
--- a/public/panels/clients.js
+++ b/public/panels/clients.js
@@ -58,6 +58,13 @@ window.MCC_PANELS['clients'] = {
`<button class="btn ghost" data-id="${esc(d.id)}">${esc(d.label)}${d.count ? ` <span class="pill" style="font-size:9px;">${d.count.toLocaleString()}</span>` : ''}</button>`).join('');
$('#cl-tabs').querySelectorAll('button').forEach(b => b.onclick = () => selectGroup(b.dataset.id));
+ // Coverage summary across the real groups (exclude the synthetic All-Prospects).
+ const real = MANIFEST.filter(x => !x.files);
+ const sum = k => real.reduce((n, x) => n + (x[k] || 0), 0);
+ const totContacts = real.reduce((n, x) => n + (x.count || 0), 0);
+ $('#cl-coverage').innerHTML = `Across <b>${real.length}</b> groups · <b>${totContacts.toLocaleString()}</b> contacts · ` +
+ `<b>${sum('with_email').toLocaleString()}</b> emails · <b>${sum('with_instagram').toLocaleString()}</b> Instagram · <b>${sum('with_linkedin').toLocaleString()}</b> LinkedIn`;
+
async function selectGroup(id) {
const d = MANIFEST.find(x => x.id === id); if (!d) return;
current = d;
diff --git a/scripts/build-clients-manifest.js b/scripts/build-clients-manifest.js
index e907bc2..7b57684 100644
--- a/scripts/build-clients-manifest.js
+++ b/scripts/build-clients-manifest.js
@@ -10,14 +10,15 @@ const DIR = path.join(__dirname, '..', 'public', 'data');
const pretty = s => s.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
const datasets = [];
+const counts = d => ({ with_email: d.with_email || 0, with_instagram: d.with_instagram || 0, with_linkedin: d.with_linkedin || 0 });
if (fs.existsSync(path.join(DIR, 'clients-fm.json'))) {
const d = JSON.parse(fs.readFileSync(path.join(DIR, 'clients-fm.json'), 'utf8'));
- datasets.push({ id: 'fm-clients', label: 'FileMaker Clients', file: 'clients-fm.json', kind: 'clients', count: d.total || (d.clients || []).length });
+ datasets.push({ id: 'fm-clients', label: 'FileMaker Clients', file: 'clients-fm.json', kind: 'clients', count: d.total || (d.clients || []).length, ...counts(d) });
}
for (const f of fs.readdirSync(DIR).filter(f => /^prospects-.*\.json$/.test(f)).sort()) {
const slug = f.replace(/^prospects-|\.json$/g, '');
const d = JSON.parse(fs.readFileSync(path.join(DIR, f), 'utf8'));
- datasets.push({ id: slug, label: pretty(slug), file: f, kind: 'prospects', count: d.total || (d.businesses || []).length });
+ datasets.push({ id: slug, label: pretty(slug), file: f, kind: 'prospects', count: d.total || (d.businesses || []).length, ...counts(d) });
}
fs.writeFileSync(path.join(DIR, 'clients-manifest.json'), JSON.stringify({ updated: new Date().toISOString().slice(0, 10), datasets }, null, 2));
console.log(`clients-manifest.json — ${datasets.length} groups:`);
← b1d1fc7 clients panel: dedup + field-merge in All Prospects (LA grou
·
back to Marketing Command Center
·
auto-save: 2026-07-16T12:13:12 (1 files) — public/data/clien 1473c68 →