Files
foodlinkk-command-center/cockpit/templates/export_intel.html
T
Aissa c5ea8cbb63 Ship War Room UX, CEO inbox, mobile chat, and Agents NAS workspace.
Make A2A togglable, keep reply context while reading, route agent data to //10.4.7.11/share/Agents, and polish themes plus export-intel sync cancel.
2026-08-16 22:40:32 +00:00

854 lines
48 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Wereldexport · Foodlinkk B2B{% endblock %}
{% block extra_head %}
<link rel="stylesheet" href="/static/vendor/leaflet/leaflet.css?v=1" />
<link rel="stylesheet" href="/static/vendor/leaflet.markercluster/MarkerCluster.css?v=1" />
<link rel="stylesheet" href="/static/vendor/leaflet.markercluster/MarkerCluster.Default.css?v=1" />
<link rel="stylesheet" href="/static/css/export-intel.css?v=23" />
<link rel="stylesheet" href="/static/css/export-intel-tabs.css?v=21" />
<script src="/static/vendor/leaflet/leaflet.js?v=1"></script>
<script src="/static/vendor/leaflet.markercluster/leaflet.markercluster.js?v=1"></script>
<script src="/static/js/export-intel-map.js?v=21"></script>
<script src="/static/js/export-intel.js?v=48"></script>
<script src="/static/js/export-intel-profile.js?v=7"></script>
{% endblock %}
{% block content %}
<div class="ei-page" x-data="exportIntelApp()" x-init="init()">
<div class="ei-progress-overlay" x-show="isWorking()" x-cloak>
<div class="ei-progress-card">
<div class="ei-progress-spinner"></div>
<p x-text="progressLabel()"></p>
<div class="ei-progress-bar"><div class="ei-progress-bar-fill" :style="'width:' + (syncMonitorPercent() || 8) + '%'"></div></div>
<div class="ei-progress-actions">
<button type="button" class="btn btn-sm ei-btn-cancel" @click="cancelSync()" x-show="busy || (syncMonitor && syncMonitor.any_running)">⏹ Annuleer sync</button>
<button type="button" class="btn btn-sm" @click="dismissOverlay()" title="Overlay sluiten — sync loopt door in monitor">Verberg</button>
</div>
</div>
</div>
<header class="ei-header page-header">
<div>
<h1>Wereldexport <span class="live-badge">Live</span></h1>
<p class="ei-subtitle">Foodlinkk B2B · wereldwijde markten · halal vlees · cateraars · distributeurs</p>
</div>
<div class="retail-actions">
<button class="btn btn-sm btn-pulse-green" @click="syncKind('world')" :disabled="busy" title="Europa · MENA · Afrika · Amerika">🌍 Sync wereld</button>
<button class="btn btn-sm btn-pulse" @click="syncKind('region')" :disabled="busy || !region" title="Sync huidige regio-filter">Sync regio</button>
<button class="btn btn-sm btn-pulse-green" @click="syncKind('all')" :disabled="busy">⚡ Sync alles</button>
<button class="btn btn-sm btn-pulse" @click="syncKind('distributors')" :disabled="busy">Distributeurs</button>
<button class="btn btn-sm btn-pulse" @click="syncKind('caterers')" :disabled="busy">Cateraars</button>
<button class="btn btn-sm btn-pulse-green" @click="syncKind('contacts')" :disabled="busy">Contacten</button>
<button class="btn btn-sm btn-pulse-purple" @click="syncKind('tenders')" :disabled="busy">TED</button>
<a class="btn btn-sm" :href="contactsExportUrl()" target="_blank">CSV export</a>
</div>
</header>
<div class="ei-sync-monitor" :class="{ 'ei-sync-monitor-open': syncMonitorOpen, 'ei-sync-monitor-active': syncMonitor && syncMonitor.any_running }">
<button type="button" class="ei-sync-monitor-toggle" @click="toggleSyncMonitor()">
<span x-show="syncMonitor && syncMonitor.any_running">⏳ Sync bezig</span>
<span x-show="!(syncMonitor && syncMonitor.any_running)">📡 Sync monitor</span>
<span class="ei-sync-monitor-badge" x-show="syncMonitor && syncMonitor.coverage" x-text="(syncMonitor.coverage.countries_with_data||0) + '/' + (syncMonitor.coverage.territories_total||0) + ' landen'"></span>
</button>
<div class="ei-sync-monitor-panel" x-show="syncMonitorOpen" x-cloak>
<div class="ei-sync-monitor-head">
<strong>Sync voortgang</strong>
<span x-show="syncMonitor && syncMonitor.any_running" class="ei-sync-live">● Live</span>
<button type="button" class="btn btn-sm ei-btn-cancel" style="margin-left:auto" @click="cancelSync()" x-show="syncMonitor && syncMonitor.any_running">⏹ Annuleer</button>
</div>
<template x-if="syncMonitor && syncMonitor.active_jobs && syncMonitor.active_jobs.length">
<div class="ei-sync-jobs">
<template x-for="j in syncMonitor.active_jobs" :key="j.id">
<div class="ei-sync-job">
<div class="ei-sync-job-title" x-text="j.label"></div>
<div class="ei-sync-job-msg" x-text="j.message || j.step || 'Bezig…'"></div>
<div class="ei-sync-job-bar"><div class="ei-sync-job-bar-fill" :style="'width:' + (j.percent||0) + '%'"></div></div>
<div class="ei-sync-job-meta" x-show="j.total" x-text="(j.current||0) + ' / ' + j.total + (j.country ? ' · ' + territoryName(j.country) : '')"></div>
</div>
</template>
</div>
</template>
<div class="ei-sync-coverage" x-show="syncMonitor && syncMonitor.coverage">
<div><span>Entiteiten</span><strong x-text="syncMonitor.coverage.entities_total||0"></strong></div>
<div><span>Landen met data</span><strong x-text="(syncMonitor.coverage.countries_with_data||0) + ' / ' + (syncMonitor.coverage.territories_total||0)"></strong></div>
<div><span>Lege landen</span><strong x-text="syncMonitor.coverage.countries_empty||0"></strong></div>
</div>
<div class="ei-sync-events" x-show="syncMonitor && syncMonitor.events && syncMonitor.events.length">
<div class="ei-sync-events-title">Laatste stappen</div>
<template x-for="(ev, idx) in (syncMonitor.events || []).slice().reverse().slice(0,12)" :key="idx">
<div class="ei-sync-event">
<span class="ei-sync-event-time" x-text="formatSyncTime(ev.ts)"></span>
<span class="ei-sync-event-text" x-text="syncEventLabel(ev)"></span>
</div>
</template>
</div>
</div>
</div>
<p class="ei-sync-msg" x-show="syncMsg" x-text="syncMsg"></p>
<div class="ei-selection-bar" x-show="showSelectionBar()" x-cloak>
<div class="ei-selection-left">
<span class="ei-selection-count" x-show="selectedIds.length" x-text="selectedIds.length + ' geselecteerd'"></span>
<span class="ei-selection-hint" x-show="!selectedIds.length" x-text="tab === 'contacts' ? 'Selecteer contacten met ☑ — organisatie gaat naar CRM' : 'Selecteer rijen met ☑ voor bulk-acties'"></span>
</div>
<div class="ei-selection-actions">
<button type="button" class="btn btn-sm" @click="toggleSelectAllVisible()" title="Alles op lijst">☑ Alles</button>
<button type="button" class="btn btn-sm" x-show="selectedIds.length" @click="clearSelection()">Wis selectie</button>
<button type="button" class="btn btn-sm btn-pulse" :disabled="!selectedIds.length || busy" @click="favoriteSelection()">★ Favoriet</button>
<button type="button" class="btn btn-sm" :disabled="!selectedIds.length || busy" @click="unfavoriteSelection()">☆ Verwijder favoriet</button>
<button type="button" class="btn btn-sm btn-pulse-green" :disabled="!selectedIds.length || crmPushBusy" @click="openCrmModal()">➕ Naar CRM</button>
</div>
</div>
<div class="ei-neo-kpi-row">
<div class="ei-neo-kpi">
<div class="ei-neo-kpi-top">
<div class="ei-neo-ring" style="--ring-color:#0ea5e9;--ring-pct:85"><div class="ei-neo-ring-inner">🌍</div></div>
<div><div class="ei-neo-kpi-label">Landen</div></div>
</div>
<div class="ei-neo-kpi-value" x-text="stats.territories||0"></div>
</div>
<div class="ei-neo-kpi">
<div class="ei-neo-kpi-top">
<div class="ei-neo-ring" style="--ring-color:#38bdf8;--ring-pct:70"><div class="ei-neo-ring-inner">📊</div></div>
<div><div class="ei-neo-kpi-label">Entities</div></div>
</div>
<div class="ei-neo-kpi-value" x-text="stats.entities||0"></div>
</div>
<div class="ei-neo-kpi">
<div class="ei-neo-kpi-top">
<div class="ei-neo-ring" style="--ring-color:#fbbf24;--ring-pct:75"><div class="ei-neo-ring-inner">📦</div></div>
<div><div class="ei-neo-kpi-label">Distributeurs</div></div>
</div>
<div class="ei-neo-kpi-value" x-text="stats.distributors||0"></div>
</div>
<div class="ei-neo-kpi">
<div class="ei-neo-kpi-top">
<div class="ei-neo-ring" style="--ring-color:#a78bfa;--ring-pct:65"><div class="ei-neo-ring-inner">🏢</div></div>
<div><div class="ei-neo-kpi-label">Cateraars</div></div>
</div>
<div class="ei-neo-kpi-value" x-text="stats.caterers||0"></div>
</div>
<div class="ei-neo-kpi">
<div class="ei-neo-kpi-top">
<div class="ei-neo-ring" style="--ring-color:#34d399;--ring-pct:60"><div class="ei-neo-ring-inner">📇</div></div>
<div><div class="ei-neo-kpi-label">Contacten</div></div>
</div>
<div class="ei-neo-kpi-value" x-text="stats.contacts||0"></div>
</div>
<div class="ei-neo-kpi">
<div class="ei-neo-kpi-top">
<div class="ei-neo-ring" style="--ring-color:#c084fc;--ring-pct:50"><div class="ei-neo-ring-inner">📋</div></div>
<div><div class="ei-neo-kpi-label">Tenders open</div></div>
</div>
<div class="ei-neo-kpi-value" x-text="stats.tenders_open||0"></div>
</div>
</div>
<div class="ei-filter-bar">
<div class="ei-filter-grid">
<label class="ei-filter-label ei-filter-cell ei-fa-regio">Regio
<select x-model="region" @change="country=''; refresh()">
<option value="">Alle regio's</option>
<template x-for="r in regions" :key="r.code">
<option :value="r.code" x-text="r.name_nl"></option>
</template>
</select>
</label>
<label class="ei-filter-label ei-filter-cell ei-fa-land">Land
<select x-model="country" @change="onCountryChange()">
<option value="">Alle landen</option>
<template x-for="t in filteredTerritories()" :key="t.country_iso2">
<option :value="t.country_iso2" x-text="countryOptionLabel(t)"></option>
</template>
</select>
</label>
<label class="ei-filter-label ei-filter-cell ei-filter-cell-search ei-fa-zoek">
<span>Zoeken</span>
<input type="search" placeholder="Organisatie, e-mail…" x-model="q" @input="onSearchInput()" />
</label>
<label class="ei-filter-label ei-filter-cell ei-fa-type" x-show="showEntityTypeFilter()">Type
<select x-model="entityTypeFilter" @change="applyEntityFilters()">
<template x-for="o in entityTypeOptions()" :key="o.v">
<option :value="o.v" x-text="o.l"></option>
</template>
</select>
</label>
<label class="ei-filter-label ei-filter-cell ei-fa-contact" x-show="showEmailFilter()">Contact
<select x-model="filterHasEmail" @change="applyEntityFilters()">
<option value="">Alle</option>
<option value="yes">Met e-mail/tel</option>
<option value="no">Zonder contact</option>
</select>
</label>
<label class="ei-filter-label ei-filter-cell ei-fa-conf" x-show="showConfidenceFilter()">Confidence
<select x-model="filterConfidenceMin" @change="applyEntityFilters()">
<option value="">Alle</option>
<option value="50">50%+</option>
<option value="70">70%+</option>
<option value="85">85%+</option>
</select>
</label>
<label class="ei-filter-label ei-filter-cell ei-fa-stad" x-show="showCityFilter()">Stad
<input type="text" placeholder="bv. Rotterdam" x-model="filterCity" @input="onCityFilterInput()" />
</label>
<label class="ei-filter-label ei-filter-cell ei-fa-extra" x-show="tab==='tenders'">Status
<select x-model="filterTenderStatus" @change="loadTabData()">
<option value="">Alle</option>
<option value="open">Open</option>
<option value="closed">Gesloten</option>
</select>
</label>
<label class="ei-filter-label ei-filter-cell ei-fa-extra" x-show="tab==='gov'">Categorie
<select x-model="filterGovCategory" @change="applyGovFilters()">
<option value="">Alle</option>
<option value="statistics">Statistiek</option>
<option value="trade">Handel</option>
<option value="regulation">Regelgeving</option>
<option value="demographics">Demografie</option>
</select>
</label>
<label class="ei-filter-label ei-filter-cell ei-fa-crm" x-show="showCollectionFilters()">CRM
<select x-model="filterCrmStatus" @change="onFilterCollectionChange()">
<option value="">Alle</option>
<option value="not_linked">Nog niet in CRM</option>
<option value="linked">In CRM</option>
</select>
</label>
<label class="ei-filter-check ei-filter-cell ei-filter-cell-check ei-fa-fav" x-show="showFavoritesFilter()">
<input type="checkbox" x-model="filterFavoritesOnly" @change="onFilterCollectionChange()" />
<span>★ Favorieten</span>
</label>
<div class="ei-filter-meta ei-filter-cell ei-filter-cell-meta ei-fa-meta">
<span class="ei-filter-count" x-show="resultCount > 0" x-text="resultCount + ' resultaten'"></span>
<span class="ei-filter-count ei-filter-fav" x-show="stats.favorites > 0" x-text="(stats.favorites||0) + ' ★'"></span>
<button type="button" class="btn btn-sm ei-filter-clear" x-show="hasActiveFilters()" @click="clearFilters()">Wis filters</button>
</div>
</div>
<div class="ei-filter-map-row" x-show="showMapTypeFilter()" x-cloak>
<span class="ei-filter-label ei-filter-map-label">Kaart toont</span>
<div class="ei-type-chips" role="group" aria-label="Types op kaart">
<button type="button" class="ei-type-chip" :class="{ active: !mapTypesSelected.length }" @click="clearMapTypes()">Alle</button>
<template x-for="chip in mapTypeChips" :key="chip.v">
<button type="button" class="ei-type-chip" :class="{ active: isMapTypeActive(chip.v) }" @click="toggleMapType(chip.v)">
<span x-text="chip.icon"></span> <span x-text="chip.l"></span> <span class="ei-chip-count" x-show="mapTypeCount(chip.v)" x-text="mapTypeCount(chip.v)"></span>
</button>
</template>
</div>
</div>
<div class="ei-filter-map-row ei-filter-map-row-halal" x-show="showMapTypeFilter()" x-cloak>
<label class="ei-filter-check">
<input type="checkbox" x-model="mapHalalMode" @change="applyMapFilters()" />
<span>🥩 Halal-kansen modus</span>
</label>
<label class="ei-filter-label ei-halal-min" x-show="mapHalalMode">
Min. score
<input type="range" min="30" max="90" step="5" x-model.number="mapHalalMin" @change="applyMapFilters()" />
<strong x-text="mapHalalMin"></strong>
</label>
</div>
</div>
<div class="vtabs-layout wereldexport-workspace" style="--vt-color:#0ea5e9" x-ref="vtabsWrap" >
<nav class="vtabs-nav" x-ref="vtabsNav" :style="'--vt-indicator-top:'+tabIndicatorTop+'px;--vt-indicator-h:'+tabIndicatorH+'px'">
<div class="vtabs-nav-header"><strong>Modules</strong></div>
<template x-for="t in tabs" :key="t.id">
<button type="button" class="vtab-btn vtab-btn-rich" :class="{active: tab===t.id}" :data-tab="t.id"
:style="'--tab-accent:'+t.color"
@click="setTab(t.id, $el)">
<span class="ei-vtab-icon-wrap" x-text="t.icon"></span>
<span class="ei-vtab-text">
<span class="ei-vtab-label" x-text="t.label"></span>
<span class="ei-vtab-sub" x-show="tabSub(t.id)" x-text="tabSub(t.id)"></span>
</span>
<span class="ei-vtab-meta">
<span class="ei-vtab-key" x-text="t.key"></span>
<span class="ei-vtab-badge" x-show="tabCount(t.id) > 0" x-text="tabCount(t.id)"></span>
</span>
</button>
</template>
</nav>
<div class="vtabs-content">
<!-- Kaart -->
<section x-show="tab==='map'" x-cloak>
<div class="ei-tab-panel">
<div class="ei-tab-panel-head">
<div>
<h2>Wereldkaart</h2>
<p>Klik pin voor preview · dubbelklik of “Volledig profiel” voor alle gegevens</p>
</div>
</div>
<div class="ei-tab-panel-body ei-workspace-body ei-workspace-body-map">
<div class="ei-map-legend">
<template x-if="!mapHalalMode">
<div class="ei-legend-row">
<span class="ei-legend-item"><i class="ei-leg-pin" style="--c:#f59e0b">📦</i> Distributeur</span>
<span class="ei-legend-item"><i class="ei-leg-pin" style="--c:#eab308">🏪</i> Groothandel</span>
<span class="ei-legend-item"><i class="ei-leg-pin" style="--c:#a78bfa">🏢</i> Cateraar</span>
<span class="ei-legend-item"><i class="ei-leg-pin" style="--c:#34d399">🍽️</i> Horeca</span>
<span class="ei-legend-item"><i class="ei-leg-pin" style="--c:#0ea5e9">📍</i> Overig</span>
</div>
</template>
<template x-if="mapHalalMode">
<div class="ei-legend-row ei-legend-halal">
<span class="ei-legend-item"><i class="ei-leg-pin" style="--c:#22c55e">●</i> Hoge kans (75+)</span>
<span class="ei-legend-item"><i class="ei-leg-pin" style="--c:#eab308">●</i> Gemiddeld (55+)</span>
<span class="ei-legend-item"><i class="ei-leg-pin" style="--c:#f97316">●</i> Matig (40+)</span>
<span class="ei-legend-item"><i class="ei-leg-pin" style="--c:#64748b">●</i> Laag</span>
</div>
</template>
</div>
<div class="ei-map-empty" x-show="tab==='map' && !entities.length && !busy" x-cloak>
<div class="ei-map-empty-inner">
<strong x-show="region || country">Nog geen data op de kaart voor deze selectie</strong>
<strong x-show="!region && !country">Zoom in of filter op regio</strong>
<p>Landen staan in het systeem, maar entities + contacten komen pas na een <em>OSM sync</em> (OpenStreetMap).</p>
<p x-show="region==='africa'">Afrika: 51 landen toegevoegd — sync nog niet gedraaid voor dit continent.</p>
<div class="ei-map-empty-actions">
<button type="button" class="btn btn-sm btn-pulse-green" x-show="region" @click="syncKind('region')" :disabled="busy">↻ Sync regio</button>
<button type="button" class="btn btn-sm btn-pulse" @click="syncKind('world')" :disabled="busy">🌍 Sync wereld</button>
</div>
</div>
</div>
<div class="ei-map-error" x-show="mapError" x-cloak x-text="mapError"></div>
<p class="ei-map-truncated" x-show="mapTruncated && !mapLoading" x-cloak>Filter actief: max. 8.000 pins op de kaart. Zoom in op regio/land voor alles.</p>
<p class="ei-map-truncated ei-map-filter-hint" x-show="resultCount === 0 && !mapLoading && (mapTypesSelected.length || entityTypeFilter)" x-cloak>Geen entities op de kaart voor dit filter — probeer B2B/groothandel of wis filters.</p>
<div class="ei-split ei-split-side">
<div class="ei-map-wrap"><div class="ei-map-loading" x-show="mapLoading" x-cloak><span class="ei-map-spinner"></span> Kaart laden…</div><div id="ei-map"></div></div>
<aside class="ei-side-panel">
<div class="ei-side-panel-head">
<h3 x-text="mapHalalMode ? 'Top halal-kansen' : 'Entities op kaart'"></h3>
<p x-show="!mapHalalMode">Klik een rij of kaart-pin om het volledige profiel te openen.</p>
<p x-show="mapHalalMode">Klik een rij voor contact & context · kaart zoomt mee.</p>
</div>
<div class="ei-side-panel-body">
<div class="ei-halal-markets" x-show="mapHalalMode && halalTopMarkets.length">
<h4>Landen met meeste kans</h4>
<template x-for="m in halalTopMarkets.slice(0,8)" :key="m.country_iso2">
<div class="ei-halal-market-row" @click="country=m.country_iso2; refresh()" style="cursor:pointer">
<span class="ei-halal-flag" x-text="m.country_iso2"></span>
<span class="ei-halal-market-name" x-text="territoryName(m.country_iso2)"></span>
<strong class="ei-halal-score" x-text="Math.round(m.combined_score||0)"></strong>
</div>
</template>
</div>
<div class="ei-table-wrap">
<table class="ei-table ei-table-compact">
<thead>
<tr>
<th class="ei-th-check"><input type="checkbox" @change="toggleSelectAllVisible()" title="Alles selecteren" /></th>
<th class="ei-th-fav">★</th>
<th class="ei-th-name">Naam</th>
<th class="ei-th-type">Type</th>
<th class="ei-th-city">Stad</th>
<th class="ei-th-contact ei-col-hide-side">Contact</th>
<th class="ei-th-score" x-show="mapHalalMode">Score</th>
<th class="ei-th-country">Land</th>
<th class="ei-th-open ei-col-hide-side"></th>
</tr>
</thead>
<tbody>
<template x-for="e in (mapHalalMode && halalTopEntities.length ? halalTopEntities : displayEntities())" :key="e.id">
<tr
:data-entity-id="e.id"
:class="{ 'ei-row-active': selected && selected.id === e.id && drawerOpen, 'ei-row-selected': isSelected(e.id), 'ei-row-crm': e.client_id }"
style="cursor:pointer"
title="Klik voor profiel"
>
<td class="ei-td-check" @click.stop>
<input type="checkbox" :checked="isSelected(e.id)" @change="toggleSelect(e.id, $event)" />
</td>
<td class="ei-td-fav" @click.stop>
<button type="button" class="ei-fav-btn" :class="{ active: e.is_favorite }" @click="toggleFavorite(e.id, e.is_favorite, $event)" x-text="e.is_favorite ? '★' : '☆'"></button>
</td>
<td class="ei-td-name">
<div class="ei-name-cell">
<button type="button" class="ei-row-open-btn" x-text="e.name" :title="e.name"></button>
<span class="ei-crm-badge" x-show="e.client_id" title="In CRM">CRM</span>
</div>
</td>
<td class="ei-td-type"><span class="ei-type-pill ei-type-pill-sm" :class="'ei-type-'+e.entity_type" x-text="typeLabel(e.entity_type)"></span></td>
<td class="ei-td-city" x-text="e.city ? (e.city + (e.country_iso2 ? ' · ' + e.country_iso2 : '')) : (e.country_iso2 || '—')"></td>
<td class="ei-td-contact ei-contact-cell" x-text="contactPreview(e)"></td>
<td class="ei-td-score" x-show="mapHalalMode"><span class="ei-halal-pill" :class="'ei-halal-'+(e.halal_score>=75?'hot':e.halal_score>=55?'warm':'mild')" x-text="Math.round(e.halal_score||0)"></span></td>
<td class="ei-td-country" x-text="territoryName(e.country_iso2) || e.country_iso2"></td>
<td class="ei-td-open"><span class="ei-open-chevron">Profiel →</span></td>
</tr>
</template>
</tbody>
</table>
</div>
<div class="ei-empty" x-show="!entities.length">
<p>Geen entities met geo in selectie.</p>
<button class="btn btn-sm btn-pulse ei-empty-cta" @click="syncKind('distributors')">Start sync — fase B vult data</button>
</div>
</div>
</aside>
</div>
</div>
</div>
</section>
<!-- Distributeurs -->
<section x-show="tab==='distributors'" x-cloak>
<div class="ei-tab-panel">
<div class="ei-tab-panel-head">
<div><h2>Distributeurs & groothandels</h2><p>OSM · website-scrape · handmatig (gratis)</p></div>
<button class="btn btn-sm btn-pulse" @click="syncKind('distributors')" :disabled="busy">↻ Sync</button>
</div>
<div class="ei-tab-panel-body ei-workspace-body">
<div class="ei-split ei-split-side">
<div class="ei-map-wrap">
<div class="ei-map-loading" x-show="tabMapLoading" x-cloak><span class="ei-map-spinner"></span> Kaart laden…</div>
<div id="ei-map-distributors"></div>
</div>
<aside class="ei-side-panel">
<div class="ei-side-panel-head">
<h3>Distributeurs op kaart</h3>
<p>Klik een pin of tabelrij voor het volledige profiel.</p>
</div>
<div class="ei-side-panel-body">
<div class="ei-table-wrap">
<table class="ei-table ei-table-compact">
<thead><tr>
<th class="ei-th-check"><input type="checkbox" @change="toggleSelectAllVisible()" title="Alles" /></th>
<th class="ei-th-name">Naam</th><th class="ei-th-type">Type</th><th class="ei-th-country">Land</th><th class="ei-th-city">Stad</th><th class="ei-th-contact ei-col-hide-side">Contact</th><th class="ei-th-conf ei-col-hide-side">Conf.</th><th class="ei-th-open ei-col-hide-side"></th>
</tr></thead>
<tbody>
<template x-for="e in displayEntities()" :key="e.id">
<tr :data-entity-id="e.id" :class="{ 'ei-row-selected': isSelected(e.id), 'ei-row-crm': e.client_id, 'ei-row-active': selected && selected.id === e.id && drawerOpen }" style="cursor:pointer" title="Klik voor profiel">
<td class="ei-td-check" @click.stop>
<input type="checkbox" :checked="isSelected(e.id)" @change="toggleSelect(e.id, $event)" />
</td>
<td class="ei-td-name">
<div class="ei-name-cell">
<button type="button" class="ei-row-open-btn" x-text="e.name" :title="e.name"></button>
<span class="ei-crm-badge" x-show="e.client_id">CRM</span>
</div>
</td>
<td class="ei-td-type"><span class="ei-type-pill ei-type-pill-sm" :class="'ei-type-'+e.entity_type" x-text="typeLabel(e.entity_type)"></span></td>
<td class="ei-td-country" x-text="territoryName(e.country_iso2) || e.country_iso2"></td>
<td class="ei-td-city" x-text="e.city ? (e.city + (e.country_iso2 ? ' · ' + e.country_iso2 : '')) : (e.country_iso2 || '—')"></td>
<td class="ei-td-contact ei-contact-cell" x-text="contactPreview(e)"></td>
<td class="ei-td-conf ei-confidence" x-text="(e.confidence||0)+'%'"></td>
<td class="ei-td-open"><span class="ei-open-chevron">Profiel →</span></td>
</tr>
</template>
</tbody>
</table>
</div>
<div class="ei-empty" x-show="!entities.length">
<p>Nog geen distributeurs in deze selectie.</p>
<button class="btn btn-sm btn-pulse" @click="syncKind('distributors')">Sync distributeurs (fase B)</button>
</div>
</div>
</aside>
</div>
</div>
</div>
</section>
<!-- Eindklanten -->
<section x-show="tab==='customers'" x-cloak>
<div class="ei-tab-panel">
<div class="ei-tab-panel-head">
<div><h2>Eindklanten</h2><p>Restaurants · döner · slagers · horeca</p></div>
<button class="btn btn-sm btn-pulse" @click="syncKind('customers')" :disabled="busy || !country">↻ Sync horeca</button>
</div>
<div class="ei-tab-panel-body ei-workspace-body">
<div class="ei-split ei-split-side">
<div class="ei-map-wrap">
<div class="ei-map-loading" x-show="tabMapLoading" x-cloak><span class="ei-map-spinner"></span> Kaart laden…</div>
<div id="ei-map-customers"></div>
</div>
<aside class="ei-side-panel">
<div class="ei-side-panel-head">
<h3>Eindklanten op kaart</h3>
<p>Klik een pin of tabelrij voor het volledige profiel.</p>
</div>
<div class="ei-side-panel-body">
<div class="ei-table-wrap">
<table class="ei-table ei-table-compact">
<thead><tr>
<th class="ei-th-check"><input type="checkbox" @change="toggleSelectAllVisible()" title="Alles" /></th>
<th class="ei-th-name">Naam</th><th class="ei-th-type">Type</th><th class="ei-th-country">Land</th><th class="ei-th-city">Stad</th><th class="ei-th-contact ei-col-hide-side">Contact</th><th class="ei-th-open ei-col-hide-side"></th>
</tr></thead>
<tbody>
<template x-for="e in displayEntities()" :key="e.id">
<tr :data-entity-id="e.id" :class="{ 'ei-row-selected': isSelected(e.id), 'ei-row-crm': e.client_id, 'ei-row-active': selected && selected.id === e.id && drawerOpen }" style="cursor:pointer" title="Klik voor profiel">
<td class="ei-td-check" @click.stop>
<input type="checkbox" :checked="isSelected(e.id)" @change="toggleSelect(e.id, $event)" />
</td>
<td class="ei-td-name">
<div class="ei-name-cell">
<button type="button" class="ei-row-open-btn" x-text="e.name" :title="e.name"></button>
<span class="ei-crm-badge" x-show="e.client_id">CRM</span>
</div>
</td>
<td class="ei-td-type"><span class="ei-type-pill ei-type-pill-sm" :class="'ei-type-'+e.entity_type" x-text="typeLabel(e.entity_type)"></span></td>
<td class="ei-td-country" x-text="territoryName(e.country_iso2) || e.country_iso2"></td>
<td class="ei-td-city" x-text="e.city ? (e.city + (e.country_iso2 ? ' · ' + e.country_iso2 : '')) : (e.country_iso2 || '—')"></td>
<td class="ei-td-contact ei-contact-cell" x-text="contactPreview(e)"></td>
<td class="ei-td-open"><span class="ei-open-chevron">Profiel →</span></td>
</tr>
</template>
</tbody>
</table>
</div>
<div class="ei-empty" x-show="!entities.length">
<p>Selecteer een land en sync horeca via OSM.</p>
</div>
</div>
</aside>
</div>
</div>
</div>
</section>
<!-- Cateraars -->
<section x-show="tab==='caterers'" x-cloak>
<div class="ei-tab-panel">
<div class="ei-tab-panel-head">
<div><h2>Facilitaire cateraars</h2><p>Albron · Sodexo · Compass · presence per land</p></div>
<button class="btn btn-sm btn-pulse" @click="syncKind('caterers')" :disabled="busy">↻ Sync</button>
</div>
<div class="ei-tab-panel-body ei-workspace-body">
<div class="ei-split ei-split-side">
<div class="ei-map-wrap">
<div class="ei-map-loading" x-show="tabMapLoading" x-cloak><span class="ei-map-spinner"></span> Kaart laden…</div>
<div id="ei-map-caterers"></div>
</div>
<aside class="ei-side-panel">
<div class="ei-side-panel-head">
<h3>Cateraars op kaart</h3>
<p>Klik een pin of tabelrij voor het volledige profiel.</p>
</div>
<div class="ei-side-panel-body">
<div class="ei-side-section">
<h4>Brand presence</h4>
<div class="ei-table-wrap">
<table class="ei-table ei-table-compact ei-table-brand">
<thead><tr><th class="ei-th-name">Brand</th><th class="ei-th-country">Land</th><th>Lokale naam</th><th>Takken</th></tr></thead>
<tbody>
<template x-for="p in catererPresence" :key="p.id">
<tr
:data-entity-id="p.entity_id || null"
:class="{ 'ei-row-active': p.entity_id && selected && selected.id === p.entity_id && drawerOpen, 'ei-row-crm': p.client_id }"
:style="p.entity_id ? 'cursor:pointer' : ''"
:title="p.entity_id ? 'Klik voor profiel' : ''"
>
<td class="ei-td-name">
<div class="ei-name-cell">
<button type="button" class="ei-row-open-btn" x-show="p.entity_id" x-text="p.brand_name"></button>
<span x-show="!p.entity_id" x-text="p.brand_name"></span>
</div>
</td>
<td class="ei-td-country" x-text="territoryName(p.country_iso2) || p.country_iso2"></td>
<td x-text="p.local_legal_name||'—'"></td>
<td x-text="(p.service_lines||[]).join(', ')"></td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<div class="ei-side-section">
<h4>Cateraar entities</h4>
<div class="ei-table-wrap">
<table class="ei-table ei-table-compact">
<thead><tr>
<th class="ei-th-name">Naam</th><th class="ei-th-type">Type</th><th class="ei-th-country">Land</th><th class="ei-th-city">Stad</th><th class="ei-th-contact ei-col-hide-side">Contact</th><th class="ei-th-conf ei-col-hide-side">Conf.</th><th class="ei-th-open ei-col-hide-side"></th>
</tr></thead>
<tbody>
<template x-for="e in displayEntities()" :key="e.id">
<tr :data-entity-id="e.id" :class="{ 'ei-row-active': selected && selected.id === e.id && drawerOpen, 'ei-row-crm': e.client_id }" style="cursor:pointer" title="Klik voor profiel">
<td class="ei-td-name">
<div class="ei-name-cell">
<button type="button" class="ei-row-open-btn" x-text="e.name" :title="e.name"></button>
<span class="ei-crm-badge" x-show="e.client_id">CRM</span>
</div>
</td>
<td class="ei-td-type"><span class="ei-type-pill ei-type-pill-sm" :class="'ei-type-'+e.entity_type" x-text="typeLabel(e.entity_type)"></span></td>
<td class="ei-td-country" x-text="territoryName(e.country_iso2) || e.country_iso2"></td>
<td class="ei-td-city" x-text="e.city ? (e.city + (e.country_iso2 ? ' · ' + e.country_iso2 : '')) : (e.country_iso2 || '—')"></td>
<td class="ei-td-contact ei-contact-cell" x-text="contactPreview(e)"></td>
<td class="ei-td-conf ei-confidence" x-text="(e.confidence||0)+'%'"></td>
<td class="ei-td-open"><span class="ei-open-chevron">Profiel →</span></td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
</aside>
</div>
</div>
</div>
</section>
<!-- Contacten -->
<section x-show="tab==='contacts'" x-cloak>
<div class="ei-tab-panel">
<div class="ei-tab-panel-head">
<div><h2>Contactregistry</h2><p>E-mail · telefoon · outreach-ready · direct naar CRM</p></div>
<div class="ei-tab-panel-actions">
<button type="button" class="btn btn-sm btn-pulse-green" :disabled="!selectedIds.length || crmPushBusy" @click="openCrmModal()">➕ Geselecteerde naar CRM</button>
<a class="btn btn-sm" :href="contactsExportUrl()" target="_blank">CSV export</a>
</div>
</div>
<div class="ei-tab-panel-body ei-workspace-body">
<div class="ei-split ei-split-side">
<div class="ei-map-wrap">
<div class="ei-map-loading" x-show="tabMapLoading" x-cloak><span class="ei-map-spinner"></span> Kaart laden…</div>
<div id="ei-map-contacts"></div>
</div>
<aside class="ei-side-panel">
<div class="ei-side-panel-head">
<h3>Contacten op kaart</h3>
<p>Klik een pin of tabelrij voor het volledige profiel.</p>
</div>
<div class="ei-side-panel-body">
<div class="ei-table-wrap">
<table class="ei-table ei-table-compact ei-table-contacts">
<thead>
<tr>
<th class="ei-th-check"><input type="checkbox" @change="toggleSelectAllVisible()" title="Alles selecteren" /></th>
<th class="ei-th-name">Organisatie</th>
<th class="ei-th-city">Stad</th>
<th class="ei-th-type">Type</th>
<th class="ei-th-country">Land</th>
<th class="ei-col-hide-side">Rol</th>
<th class="ei-col-hide-side ei-th-name">Naam</th>
<th class="ei-col-hide-side">E-mail</th>
<th class="ei-col-hide-side">Telefoon</th>
<th class="ei-col-hide-side">CRM</th>
<th class="ei-th-open ei-col-hide-side"></th>
<th></th>
</tr>
</thead>
<tbody>
<template x-for="c in contacts" :key="c.id">
<tr :data-entity-id="c.entity_id" :class="{ 'ei-row-selected': isSelected(c.entity_id), 'ei-row-crm': c.client_id, 'ei-row-active': selected && selected.id === c.entity_id && drawerOpen }" style="cursor:pointer" title="Klik voor profiel">
<td class="ei-td-check" @click.stop>
<input type="checkbox" :checked="isSelected(c.entity_id)" @change="toggleSelect(c.entity_id, $event)" />
</td>
<td class="ei-td-name">
<div class="ei-name-cell">
<button type="button" class="ei-row-open-btn" x-text="c.entity_name" :title="c.entity_name"></button>
<span class="ei-crm-badge" x-show="c.client_id">CRM</span>
</div>
</td>
<td class="ei-td-city" x-text="c.entity_city ? (c.entity_city + (c.country_iso2 ? ' · ' + c.country_iso2 : '')) : (c.country_iso2 || '—')"></td>
<td class="ei-td-type"><span class="ei-type-pill ei-type-pill-sm" :class="'ei-type-'+c.entity_type" x-text="typeLabel(c.entity_type)"></span></td>
<td class="ei-td-country" x-text="territoryName(c.country_iso2) || c.country_iso2"></td>
<td class="ei-col-hide-side" x-text="c.role || '—'"></td>
<td class="ei-col-hide-side" x-text="c.name||'—'"></td>
<td class="ei-col-hide-side" x-text="c.email||'—'"></td>
<td class="ei-col-hide-side" x-text="c.phone||c.mobile||'—'"></td>
<td class="ei-col-hide-side">
<span class="ei-crm-badge" x-show="c.client_id" :title="c.crm_client_name || 'In CRM'">CRM</span>
<span class="muted" x-show="!c.client_id">—</span>
</td>
<td class="ei-td-open"><span class="ei-open-chevron">Profiel →</span></td>
<td class="ei-td-actions" @click.stop>
<button type="button" class="btn btn-sm btn-pulse-green" x-show="!c.client_id" @click="pushEntityToCrm(c.entity_id)" :disabled="crmPushBusy">➕ CRM</button>
<a class="btn btn-sm" x-show="c.client_id" :href="'/clients'" title="Bekijk in CRM">Open</a>
</td>
</tr>
</template>
</tbody>
</table>
</div>
<div class="ei-load-more" x-show="contactsHasMore">
<button type="button" class="btn btn-sm" @click="loadMoreContacts()" :disabled="contactsLoadingMore || busy">
<span x-text="contactsLoadingMore ? 'Laden…' : ('Meer laden (' + contacts.length + ' / ' + resultCount + ')')"></span>
</button>
</div>
<div class="ei-empty" x-show="!contacts.length && !busy">
<p>Geen contacten voor deze filters — pas land, type of zoekterm aan.</p>
<button class="btn btn-sm btn-pulse-green" @click="syncKind('contacts')">Sync contacten</button>
</div>
</div>
</aside>
</div>
</div>
</div>
</section>
<!-- Tenders -->
<section x-show="tab==='tenders'" x-cloak>
<div class="ei-tab-panel">
<div class="ei-tab-panel-head">
<div><h2>Tenders</h2><p>TED API · food · catering · meat</p></div>
<button class="btn btn-sm btn-pulse-purple" @click="syncKind('tenders')" :disabled="busy">↻ TED sync</button>
</div>
<div class="ei-tab-panel-body">
<div class="ei-panel" style="border:none;background:transparent;padding:0">
<div class="ei-table-wrap">
<table class="ei-table ei-table-compact">
<thead><tr><th>Titel</th><th class="ei-th-country">Land</th><th>Status</th><th>Link</th></tr></thead>
<tbody>
<template x-for="t in tenders" :key="t.id">
<tr>
<td x-text="t.title"></td>
<td x-text="territoryName(t.country_iso2) || t.country_iso2||'—'"></td>
<td x-text="t.status"></td>
<td><a :href="t.url" target="_blank" rel="noopener">Open</a></td>
</tr>
</template>
</tbody>
</table>
</div>
<div class="ei-empty" x-show="!tenders.length">
<p>Geen tenders — klik TED sync.</p>
</div>
</div>
</div>
</div>
</section>
<!-- Overheid -->
<section x-show="tab==='gov'" x-cloak>
<div class="ei-tab-panel">
<div class="ei-tab-panel-head">
<div><h2>Overheid & data</h2><p>Statistiek · tender portals per land</p></div>
</div>
<div class="ei-tab-panel-body">
<div class="ei-panel" style="border:none;background:transparent;padding:0">
<div class="ei-table-wrap">
<table class="ei-table ei-table-compact">
<thead><tr><th class="ei-th-country">Land</th><th class="ei-th-name">Naam</th><th>Categorie</th><th>Link</th></tr></thead>
<tbody>
<template x-for="g in govSources" :key="g.id">
<tr>
<td x-text="territoryName(g.country_iso2) || g.country_iso2"></td>
<td x-text="g.name"></td>
<td x-text="g.category"></td>
<td><a :href="g.url" target="_blank" rel="noopener">Open</a></td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
</div>
</div>
</section>
<!-- Pipeline -->
<section x-show="tab==='pipeline'" x-cloak>
<div class="ei-tab-panel">
<div class="ei-tab-panel-head">
<div><h2>CRM Pipeline</h2><p>Van Wereldexport naar klanten & deals</p></div>
<div class="retail-actions">
<button type="button" class="btn btn-sm btn-pulse-green" :disabled="!selectedIds.length" @click="openCrmModal()">➕ Geselecteerde naar CRM</button>
<a class="btn btn-sm btn-pulse" href="/clients">Klanten</a>
<a class="btn btn-sm btn-pulse" href="/deals">Deals</a>
</div>
</div>
<div class="ei-tab-panel-body ei-workspace-body">
<div class="ei-split ei-split-side">
<div class="ei-map-wrap">
<div class="ei-map-loading" x-show="tabMapLoading" x-cloak><span class="ei-map-spinner"></span> Kaart laden…</div>
<div id="ei-map-pipeline"></div>
</div>
<aside class="ei-side-panel">
<div class="ei-side-panel-head">
<h3>CRM pipeline op kaart</h3>
<p>Klik een pin of tabelrij voor het volledige profiel.</p>
</div>
<div class="ei-side-panel-body">
<p class="ei-side-hint ei-pipeline-hint">Entities via <strong>Naar CRM</strong> — koppeling naar klant + deal.</p>
<div class="ei-table-wrap" x-show="crmPipeline.length">
<table class="ei-table ei-table-compact ei-table-pipeline">
<thead>
<tr>
<th class="ei-th-name">Organisatie</th>
<th class="ei-th-type">Type</th>
<th class="ei-th-country">Land</th>
<th class="ei-th-pipe-meta">CRM klant</th>
<th class="ei-th-pipe-meta">Deal</th>
<th class="ei-th-pipe-meta">Datum</th>
<th class="ei-th-open ei-col-hide-side"></th>
</tr>
</thead>
<tbody>
<template x-for="p in displayPipeline()" :key="p.id">
<tr :data-entity-id="p.id" :class="{ 'ei-row-active': selected && selected.id === p.id && drawerOpen, 'ei-row-crm': p.client_id }" style="cursor:pointer" title="Klik voor profiel">
<td class="ei-td-name">
<div class="ei-name-cell">
<button type="button" class="ei-row-open-btn" x-text="p.name" :title="p.name"></button>
<span class="ei-crm-badge" x-show="p.client_id">CRM</span>
</div>
</td>
<td class="ei-td-type"><span class="ei-type-pill ei-type-pill-sm" :class="'ei-type-'+p.entity_type" x-text="typeLabel(p.entity_type)"></span></td>
<td class="ei-td-country" x-text="territoryName(p.country_iso2) || p.country_iso2"></td>
<td class="ei-td-pipe-meta">
<a x-show="p.client_id" :href="'/clients'" @click.stop x-text="p.crm_client_name || ('#'+p.client_id)"></a>
</td>
<td class="ei-td-pipe-meta" x-text="p.crm_deal_title || '—'"></td>
<td class="ei-td-pipe-meta" x-text="p.crm_pushed_at ? new Date(p.crm_pushed_at).toLocaleDateString('nl-NL') : '—'"></td>
<td class="ei-td-open"><span class="ei-open-chevron">Profiel →</span></td>
</tr>
</template>
</tbody>
</table>
</div>
<div class="ei-empty" x-show="!crmPipeline.length">
<p>Nog geen entities in CRM vanuit Wereldexport.</p>
<p>Selecteer leads op de kaart en klik <strong>➕ Naar CRM</strong>.</p>
</div>
</aside>
</div>
</div>
</div>
</section>
</div>
</div>
<!-- Profiel popup (modal) — content rendered by ExportIntelProfile JS -->
<div id="ei-profile-modal" class="ei-profile-modal-root" aria-hidden="true">
<div class="ei-profile-backdrop" data-ei-action="close"></div>
<div class="ei-profile-panel" role="dialog" aria-modal="true" aria-labelledby="ei-profile-title">
<div id="ei-profile-mount"></div>
</div>
</div>
<!-- CRM bevestiging -->
<div class="ei-modal-root" x-show="crmModalOpen" x-cloak>
<div class="ei-drawer-backdrop" @click="crmModalOpen=false"></div>
<div class="ei-modal-card">
<h3>Toevoegen aan CRM</h3>
<p><strong x-text="selectedIds.length"></strong> organisatie(s) worden klant in CRM.</p>
<label class="ei-filter-check">
<input type="checkbox" x-model="crmCreateDeals" />
<span>Maak ook een deal per klant (aanbevolen)</span>
</label>
<p class="ei-modal-note">Bestaande klanten met hetzelfde e-mailadres worden gekoppeld i.p.v. dubbel aangemaakt.</p>
<div class="ei-modal-actions">
<button type="button" class="btn btn-sm" @click="crmModalOpen=false">Annuleren</button>
<button type="button" class="btn btn-sm btn-pulse-green" @click="pushToCrm()" :disabled="crmPushBusy">
<span x-text="crmPushBusy ? 'Bezig…' : 'Bevestig → CRM'"></span>
</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}{% endblock %}