← back to Rentv
crm: wider LinkedIn match (first+last token, catches middle-initial/nickname variants) — 10→16
37698626fa6095f7f531e73751b71c2ac25c9fb1 · 2026-08-12 17:51:17 -0700 · Steve Abrams
Files touched
Diff
commit 37698626fa6095f7f531e73751b71c2ac25c9fb1
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Aug 12 17:51:17 2026 -0700
crm: wider LinkedIn match (first+last token, catches middle-initial/nickname variants) — 10→16
---
server.js | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/server.js b/server.js
index 7fff9ea1..777f4a2a 100644
--- a/server.js
+++ b/server.js
@@ -2365,11 +2365,12 @@ function liNorm(s){
t = t.replace(/\b(aia|ccim|sior|mba|esq|jr|sr|ii|iii|iv|cpm|leed|ap|phd|md|mai|rpa|cfa|cpa|mrics|frics|pe|rid|ncidq|gri|abr|crs)\b/g, ' ').replace(/\s+/g, ' ').trim();
return t;
}
+function liFirstLast(s){ const p = liNorm(s).split(' ').filter(Boolean); return p.length >= 2 ? p[0] + ' ' + p[p.length - 1] : ''; }
function loadLinkedInFollows() {
- const set = new Set();
+ const names = [];
try {
const j = JSON.parse(fs.readFileSync(path.join(DATA, 'linkedin-follows.json'), 'utf8'));
- for (const x of (Array.isArray(j) ? j : [])) { const n = typeof x === 'string' ? x : (x && x.name); if (n) set.add(liNorm(n)); }
+ for (const x of (Array.isArray(j) ? j : [])) { const n = typeof x === 'string' ? x : (x && x.name); if (n) names.push(n); }
} catch { /* no json */ }
try {
const lines = fs.readFileSync(path.join(DATA, 'linkedin-connections.csv'), 'utf8').split(/\r?\n/);
@@ -2383,11 +2384,13 @@ function loadLinkedInFollows() {
const f = lines[i].match(/("([^"]|"")*"|[^,]*)(,|$)/g) || [];
const cell = k => (f[k] || '').replace(/,$/, '').replace(/^"|"$/g, '').replace(/""/g, '"').trim();
const nm = ni >= 0 ? cell(ni) : [cell(fi), cell(li2)].filter(Boolean).join(' ');
- if (nm) set.add(liNorm(nm));
+ if (nm) names.push(nm);
}
}
} catch { /* no csv */ }
- return set;
+ const full = new Set(), fl = new Set();
+ for (const n of names) { const nn = liNorm(n); if (nn) full.add(nn); const f = liFirstLast(n); if (f) fl.add(f); }
+ return { full, fl };
}
app.get('/api/crm', adminOnly, async (req, res) => {
try {
@@ -2408,7 +2411,8 @@ app.get('/api/crm', adminOnly, async (req, res) => {
const all = [...ownedContacts, ...commercial, ...owners, ...directory].map((c) => ({
...c,
// green-highlight flag: is this person someone Steve already follows/connects with on LinkedIn?
- li_follow: !!(c.name && liFollows.has(liNorm(c.name))),
+ // exact normalized full-name match, OR first+last-token match (catches middle-initial/nickname variants).
+ li_follow: !!(c.name && (liFollows.full.has(liNorm(c.name)) || (liFirstLast(c.name) && liFollows.fl.has(liFirstLast(c.name))))),
// one precomputed lowercase search blob per contact (no per-keystroke JSON.stringify).
_s: [c.name, c.firm, c.email, c.phone, c.city, c.title, c.interest, c.source, c.dre_license, c.ain, c.list_category, c.address].filter(Boolean).join(' ').toLowerCase(),
}));
← 389655dc crm: strip credential suffixes (AIA/CCIM/SIOR/MBA…) when mat
·
back to Rentv
·
fix(desk): answer /favicon.ico with 204 to silence console 4 37140366 →