← back to Rentv
mockups/admin/admin-core.js
42 lines
/* RENTV admin core — shared across the 10 back-office layouts (A01..A10).
Owns: the real click-out action URLs (LinkedIn/website/Maps/firm/CA-DRE),
the broker/firm/owner data loader, and the inline action-button block.
Each A##.html supplies only its unique layout + render(). */
window.ADM = (function () {
const enc = encodeURIComponent, esc = s => String(s == null ? '' : s).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]));
// ── real, functional click-outs ──
const LI_P = (n, f) => `https://www.linkedin.com/search/results/people/?keywords=${enc([n, f].filter(Boolean).join(' '))}`;
const LI_C = f => `https://www.linkedin.com/search/results/companies/?keywords=${enc(f)}`;
const WEB = f => `https://www.google.com/search?q=${enc('"' + f + '" real estate official website')}`;
const MAPS = q => `https://www.google.com/maps/search/?api=1&query=${enc(q)}`;
const DRE = lic => `https://www2.dre.ca.gov/PublicASP/pplinfo.asp?License_id=${enc(lic)}`;
const GOOG = q => `https://www.google.com/search?q=${enc(q)}`;
const ASSR = ain => `https://portal.assessor.lacounty.gov/parceldetail/${enc(ain)}`;
const loc = x => [x.city || x.hq_city, x.state_code || x.hq_state].filter(Boolean).join(', ');
const A = (href, icon, label) => `<a class="act" href="${href}" target="_blank" rel="noopener" onclick="event.stopPropagation()"><span class="i">${icon}</span>${label}</a>`;
// the inline action set for any record kind — the "like CRCP" click-outs
function actions(kind, x) {
if (kind === 'firms') return [A(LI_C(x.name), '🏢', 'LinkedIn'), A(WEB(x.name), '🌐', 'Website'), A(MAPS(x.name + ' ' + loc(x)), '📍', 'HQ / Map'), x.license_no ? A(DRE(x.license_no), '🪪', 'DRE') : '', A(GOOG(x.name + ' brokers ' + loc(x)), '🔎', 'Google')].filter(Boolean).join('');
if (kind === 'owners') { const addr = [x.address, x.city].filter(Boolean).join(', '); return [A(MAPS(addr), '📍', 'Map'), A(GOOG(addr + ' ' + (x.use_desc || '') + ' owner'), '🔎', 'Owner / deal'), A('https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=' + enc(addr), '📸', 'Street View'), A(ASSR(x.ain), '🏛️', 'Assessor')].join(''); }
return [A(LI_P(x.name, x.firm_name), '👤', 'LinkedIn'), A(GOOG(x.name + ' ' + (x.firm_name || '') + ' ' + loc(x)), '🔎', 'Google'), x.firm_name ? A(WEB(x.firm_name), '🌐', 'Firm site') : '', x.firm_name ? A(LI_C(x.firm_name), '🏢', 'Firm') : '', loc(x) ? A(MAPS((x.firm_name || x.name) + ' ' + loc(x)), '📍', 'Map') : '', x.license_no ? A(DRE(x.license_no), '🪪', 'DRE') : ''].filter(Boolean).join('');
}
const nm = x => x.name || x.address || x.ain;
const sub = (kind, x) => kind === 'brokers' ? (x.firm_name || '—') : kind === 'firms' ? ((x.agent_count || 0).toLocaleString() + ' agents') : (x.type_label || '');
async function load() {
const get = (f, fb) => fetch('data/' + f).then(r => r.json()).catch(() => fb);
const [b, f, la] = await Promise.all([get('brokers.json', { rows: [] }), get('firms.json', { rows: [] }), get('la-commercial.json', { marquee: [] })]);
return {
brokers: b.rows || [], firms: f.rows || [], owners: la.marquee || [],
totalB: b.total || (b.rows || []).length, totalF: f.total || (f.rows || []).length,
};
}
// preload data FIRST, then mount chrome with a synchronous render → numbering sees the full DOM
async function mount(layout, render) {
const d = await load();
RENTV.mount({ dark: true, layout, render: () => render(d) });
}
return { esc, LI_P, LI_C, WEB, MAPS, DRE, GOOG, ASSR, loc, A, actions, nm, sub, load, mount };
})();