/** * Export Intel β€” profiel popup (imperatief, geen Alpine in modal). */ (function (global) { 'use strict'; function normalizeWebUrl(u) { if (!u) return ''; u = String(u).trim(); if (!u) return ''; if (!/^https?:\/\//i.test(u)) u = 'https://' + u.replace(/^\/+/, ''); return u; } function contactGapHint(e) { var r = e.reach || {}; var hasDirect = !!(e.phone || e.email || e.website || (r.phones && r.phones.length) || (r.emails && r.emails.length) || (r.websites && r.websites.length)); if (hasDirect) return ''; var src = e.source || 'osm'; return '

Geen telefoon of e-mail in bron (' + esc(src) + '). Gratis opties: Bewerken (handmatig), of Sync contacten (scant websites) / Sync distributeurs (haalt OSM-tags opnieuw).

'; } function reachSectionHtml(e) { var r = e.reach || {}; var html = ''; function links(title, items, render) { if (!items || !items.length) return; html += '
' + esc(title) + '
'; for (var i = 0; i < items.length; i++) html += render(items[i]); html += '
'; } links('E-mail', r.emails, function (it) { return '
' + esc(it.label || 'E-mail') + '' + esc(it.value) + '
'; }); links('Telefoon', r.phones, function (it) { return '
' + esc(it.label || 'Tel') + '' + esc(it.value) + '
'; }); if (!r.emails || !r.emails.length) { if (e.email) html += '
E-mail' + esc(e.email) + '
'; } if (!r.phones || !r.phones.length) { if (e.phone) html += '
Telefoon' + esc(e.phone) + '
'; } html += websitesHtml(e); links('Adres', r.addresses, function (it) { return '
' + esc(it.label || 'Adres') + '' + esc(it.value) + '
'; }); links('Social', r.social, function (it) { return '
' + esc(it.label || 'Link') + '' + esc(it.value) + '
'; }); if (r.maps_url) { html += '
MapsGoogle Maps β†’
'; } return html; } function websitesHtml(e) { var sites = e.websites; if ((!sites || !sites.length) && e.website) { sites = [{ label: 'Organisatie', url: e.website, display: e.website }]; } if (!sites || !sites.length) return ''; var rows = ''; for (var i = 0; i < sites.length; i++) { var s = sites[i]; var href = normalizeWebUrl(s.url || s); if (!href) continue; rows += '
' + esc(s.label || 'Website') + '' + '' + esc(s.display || s.url || href) + '
'; } return rows; } function esc(s) { if (s == null) return ''; return String(s) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function typeLabel(t) { return (t || '').replace(/_/g, ' '); } function getApp() { return global.__exportIntelApp || null; } function territoryName(iso2) { var app = getApp(); if (!iso2) return ''; if (app && app.territories) { for (var i = 0; i < app.territories.length; i++) { if (app.territories[i].country_iso2 === iso2) return app.territories[i].name_nl; } } return iso2; } function formatCoords(lat, lon) { if (lat == null || lon == null) return ''; var a = Number(lat); var b = Number(lon); if (!Number.isFinite(a) || !Number.isFinite(b)) return ''; return a.toFixed(5) + ', ' + b.toFixed(5); } function mountEl() { return document.getElementById('ei-profile-mount'); } function activeMapId(app) { if (!app) return 'ei-map'; if (app.tab === 'map') return 'ei-map'; if (app.tabMapId && typeof app.tabMapId === 'function') { return app.tabMapId() || 'ei-map'; } return 'ei-map-' + (app.tab || 'map'); } var Profile = { _busy: false, showShell: function (on) { var el = document.getElementById('ei-profile-modal'); if (!el) return; if (on) { el.classList.add('is-open'); el.setAttribute('aria-hidden', 'false'); document.body.classList.add('ei-profile-open'); } else { el.classList.remove('is-open'); el.setAttribute('aria-hidden', 'true'); document.body.classList.remove('ei-profile-open'); } }, clearMount: function () { var m = mountEl(); if (m) m.innerHTML = ''; }, renderLoading: function () { var m = mountEl(); if (!m) return; m.innerHTML = '
' + '' + '

Profiel laden…

'; }, renderError: function (msg) { var m = mountEl(); if (!m) return; m.innerHTML = '
' + '

' + esc(msg || 'Laden mislukt') + '

' + '
'; }, patchEntityInApp: function (app, entity) { if (!app || !entity || !entity.id) return; var id = entity.id; if (Array.isArray(app.entities)) { for (var i = 0; i < app.entities.length; i++) { if (app.entities[i].id === id) { Object.assign(app.entities[i], entity); } } } if (Array.isArray(app.crmPipeline)) { for (var j = 0; j < app.crmPipeline.length; j++) { if (app.crmPipeline[j].id === id) { Object.assign(app.crmPipeline[j], entity); } } } if (Array.isArray(app.halalTopEntities)) { for (var k = 0; k < app.halalTopEntities.length; k++) { if (app.halalTopEntities[k].id === id) { Object.assign(app.halalTopEntities[k], entity); } } } }, renderFull: function (e, app) { var m = mountEl(); if (!m || !e) return; app = app || getApp(); var contacts = e.contacts || []; var contactRows = ''; for (var i = 0; i < contacts.length; i++) { var c = contacts[i]; contactRows += '
' + '' + esc(c.name || c.role || 'Contact') + '' + (c.role ? '' + esc(c.role) + '' : '') + (c.email ? '
πŸ“§ ' + esc(c.email) + '
' : '') + (c.phone ? '
πŸ“ž ' + esc(c.phone) + '
' : '') + (c.website_contact_url ? '
🌐 ' + esc(c.website_contact_url) + '
' : '') + (c.linkedin_url ? '
in LinkedIn
' : '') + '
'; } var halalTags = ''; var labels = e.halal_reason_labels || []; for (var j = 0; j < labels.length; j++) { halalTags += '' + esc(labels[j]) + ''; } var crmBtn = e.client_id ? 'βœ“Open CRM' + esc(e.crm_client_name || ('Klant #' + e.client_id)) + '' : ''; var mapsBtn = e.maps_url ? 'πŸ“MapsLocatie' : ''; var dealBtn = e.deal_id ? 'πŸ’ΌDealPipeline' : ''; var favOn = !!e.is_favorite; m.innerHTML = '
' + '
' + '
' + '' + esc(typeLabel(e.entity_type)) + '' + '' + esc(e.country_iso2) + '' + (e.client_id ? 'In CRM' : '') + (favOn ? 'β˜… Favoriet' : '') + (e.halal_score != null ? '' + Math.round(Number(e.halal_score)) + '/100' : '') + '
' + '' + '
' + '

' + esc(e.name) + '

' + '

' + esc(territoryName(e.country_iso2)) + ' Β· Confidence ' + (e.confidence || 0) + '%' + ' Β· Pipeline ' + esc(e.pipeline_stage || 'β€”') + '' + ' Β· Bron ' + esc(e.source || 'β€”') + '

' + '
' + '
' + crmBtn + '' + '' + mapsBtn + '' + dealBtn + 'πŸ“‹Herman' + '
' + '
' + (halalTags ? '
' + halalTags + '
' : '') + ((e.city || e.address_line || (e.lat && e.lon)) ? '

Locatie

' + (e.address_line ? '

' + esc(e.address_line) + '

' : '') + (e.city ? '

' + esc(e.city) + (e.postal_code ? ', ' + esc(e.postal_code) : '') + '

' : '') + ((e.lat && e.lon) ? '

' + esc(formatCoords(e.lat, e.lon)) + (e.maps_url ? ' Maps β†’' : '') + '

' : '') + '
' : '') + '

Contact & web

' + reachSectionHtml(e) + contactGapHint(e) + ((!e.reach || !e.reach.has_any) && !e.email && !e.phone && !(e.websites && e.websites.length) && !e.website && !contacts.length ? '

Geen contact β€” sync contacten om te verrijken.

' : '') + '
' + (e.client_id ? '

CRM

' + '' + (e.crm_deal_title ? '
Deal' + esc(e.crm_deal_title) + '
' : '') + '
' : '') + '

Contactpersonen (' + contacts.length + ')

' + (contactRows || '

Geen contactpersonen.

') + '
'; if (app) { app.selected = e; app.drawerOpen = true; app.drawerLoading = false; app.listFocusDetail = e; app.listFocusId = e.id; } }, fetchEntity: function (id) { return fetch('/api/export-intel/entities/' + id).then(function (r) { return r.json().then(function (d) { if (!r.ok) throw new Error(d.error || d.detail || ('HTTP ' + r.status)); if (d && d.error) throw new Error(d.error); return d; }); }); }, highlightOnMap: function (entity, app) { if (!entity || !entity.lat || !entity.lon || !global.ExportIntelMap) return; try { var mapId = activeMapId(app); global.ExportIntelMap.flyTo(entity.lat, entity.lon, 14, mapId); global.ExportIntelMap.highlightEntity(entity.id, mapId); } catch (e) { /* ignore */ } }, open: function (id) { id = Number(id); if (!Number.isFinite(id) || id <= 0) return; if (this._busy) return; this._busy = true; this.showShell(true); this.renderLoading(); var self = this; var app = getApp(); this.fetchEntity(id) .then(function (entity) { self.renderFull(entity, app); self.highlightOnMap(entity, app); }) .catch(function (err) { self.renderError(err.message || 'Profiel laden mislukt'); }) .finally(function () { self._busy = false; }); }, close: function () { this._busy = false; this.showShell(false); this.clearMount(); var app = getApp(); if (app) { app.drawerOpen = false; app.drawerLoading = false; app.selected = null; app.editMode = false; } }, setFavorite: function (id, currentlyFavorite) { var self = this; var app = getApp(); id = Number(id); if (!Number.isFinite(id)) return Promise.reject(new Error('Ongeldig id')); return fetch('/api/export-intel/entities/favorites', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ entity_ids: [id], favorite: !currentlyFavorite }), }) .then(function (r) { return r.json().then(function (d) { if (!r.ok) throw new Error((d && (d.error || d.detail)) || 'Favoriet mislukt'); return d; }); }) .then(function () { return self.fetchEntity(id); }) .then(function (entity) { if (app) { app.selected = entity; app.listFocusDetail = entity; app.listFocusId = entity.id; app.syncMsg = entity.is_favorite ? 'β˜… Favoriet opgeslagen' : 'Favoriet verwijderd'; if (app.stats && typeof app.stats.favorites === 'number') { app.stats.favorites += entity.is_favorite ? 1 : -1; if (app.stats.favorites < 0) app.stats.favorites = 0; } self.patchEntityInApp(app, entity); } self.renderFull(entity, app); return entity; }); }, doCrm: function (id) { var self = this; var app = getApp(); id = Number(id); if (!app || !app.pushEntityToCrm) return; app.pushEntityToCrm(id).then(function () { return self.fetchEntity(id); }).then(function (entity) { if (app) { app.selected = entity; app.listFocusDetail = entity; self.patchEntityInApp(app, entity); } self.renderFull(entity, app); }).catch(function (err) { if (app) app.syncMsg = 'CRM mislukt: ' + (err.message || err); }); }, doEdit: function () { var app = getApp(); if (!app || !app.selected) return; app.startEdit(); this.renderEdit(app); }, renderEdit: function (app) { var e = app.selected; var f = app.editForm || {}; var m = mountEl(); if (!m || !e) return; m.innerHTML = '
' + '

Bewerken Β· ' + esc(e.name) + '

' + '
' + '
' + '
' + '' + '' + '' + '' + '' + '
' + '' + '' + '
'; }, saveEdit: function () { var app = getApp(); if (!app || !app.selected) return; var self = this; app.editForm.name = (document.getElementById('ei-edit-name') || {}).value || ''; app.editForm.city = (document.getElementById('ei-edit-city') || {}).value || ''; app.editForm.email = (document.getElementById('ei-edit-email') || {}).value || ''; app.editForm.phone = (document.getElementById('ei-edit-phone') || {}).value || ''; app.editForm.website = (document.getElementById('ei-edit-website') || {}).value || ''; var id = app.selected.id; Promise.resolve(app.saveEdit()).then(function () { return self.fetchEntity(id); }).then(function (entity) { if (app) { app.selected = entity; app.listFocusDetail = entity; self.patchEntityInApp(app, entity); } self.renderFull(entity, app); }); }, cancelEdit: function () { var app = getApp(); if (!app) return; app.cancelEdit(); if (app.selected) this.renderFull(app.selected, app); }, doFavorite: function (id, isFav) { var self = this; this.setFavorite(id, isFav).catch(function (err) { self.renderError(err.message || 'Favoriet mislukt'); }); }, doSyncContacts: function () { var app = getApp(); if (app && app.syncKind) app.syncKind('contacts'); }, onModalClick: function (ev) { var t = ev.target; if (!t || !t.closest) return; if (!t.closest('#ei-profile-modal')) return; if (t.closest('.ei-profile-backdrop')) { ev.preventDefault(); this.close(); return; } var actionEl = t.closest('[data-ei-action]'); if (!actionEl) return; var action = actionEl.getAttribute('data-ei-action'); if (!action) return; ev.preventDefault(); ev.stopPropagation(); var id = Number(actionEl.getAttribute('data-ei-id') || (getApp() && getApp().selected && getApp().selected.id)); if (action === 'close') this.close(); else if (action === 'crm') this.doCrm(id); else if (action === 'edit') this.doEdit(); else if (action === 'favorite') { var isFav = actionEl.getAttribute('data-ei-fav') === '1'; this.doFavorite(id, isFav); } else if (action === 'sync-contacts') this.doSyncContacts(); else if (action === 'save-edit') this.saveEdit(); else if (action === 'cancel-edit') this.cancelEdit(); }, onRowClick: function (ev) { var t = ev.target; if (!t || !t.closest) return; if (t.closest('#ei-profile-modal')) return; if (t.closest('.ei-td-check, input[type=checkbox], .ei-fav-btn, .ei-td-actions')) return; if (t.closest('a[href]') && !t.closest('.ei-row-open-btn, .ei-link-btn')) return; var row = t.closest('[data-entity-id]'); if (!row) return; var id = row.getAttribute('data-entity-id'); if (!id) return; ev.preventDefault(); ev.stopPropagation(); this.open(id); }, bindApp: function (app) { if (!app) return; global.__exportIntelApp = app; var self = this; app.openEntity = function (id) { self.open(id); }; app.closeDrawer = function () { self.close(); }; }, wireModal: function () { var modal = document.getElementById('ei-profile-modal'); if (!modal || modal._eiWired) return; modal._eiWired = true; var self = this; modal.addEventListener('click', function (ev) { self.onModalClick(ev); }, true); }, boot: function () { var self = this; this.wireModal(); document.addEventListener('click', function (ev) { self.onRowClick(ev); }, true); document.addEventListener('keydown', function (ev) { if (ev.key === 'Escape') { var modal = document.getElementById('ei-profile-modal'); if (modal && modal.classList.contains('is-open')) self.close(); } }); var params = new URLSearchParams(global.location.search); var openId = params.get('open'); function tryBind() { var page = document.querySelector('.ei-page'); if (page && page._x_dataStack && page._x_dataStack[0]) { self.bindApp(page._x_dataStack[0]); if (openId) self.open(openId); return true; } if (global.__exportIntelApp) { self.bindApp(global.__exportIntelApp); if (openId) self.open(openId); return true; } return false; } if (!tryBind()) { var n = 0; var timer = setInterval(function () { n++; if (tryBind() || n > 120) clearInterval(timer); }, 100); } document.addEventListener('alpine:initialized', function () { tryBind(); }); }, }; global.ExportIntelProfile = Profile; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function () { Profile.boot(); }); } else { Profile.boot(); } })(window);