Files
mek-tech-consulting/routes/market-intel.ejs
T

131 lines
12 KiB
Plaintext

<!DOCTYPE html><html lang="nl"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Markt Intelligence — Mek-Tech</title><link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/css/style.css"><link rel="stylesheet" href="/css/dynamic.css"><link rel="icon" href="/img/favicon.svg"><script src="https://unpkg.com/lucide@latest"></script>
<style>
.mi-wrap{max-width:1300px;margin:0 auto;padding:1.25rem 1.5rem 3rem}
.mi-hdr h1{font-size:1.5rem;font-weight:800;color:var(--text);letter-spacing:-.3px}
.mi-hdr .sub{font-size:.78rem;color:var(--text-muted)}
.mi-kpi{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:.5rem;margin:1rem 0}
.mi-kpi .mk{border:1px solid var(--border);border-radius:var(--radius);padding:.6rem .8rem;background:var(--bg-card)}
.mi-kpi .mk b{font-size:1.2rem;color:var(--text);display:block}.mi-kpi .mk span{font-size:.6rem;color:var(--text-muted);text-transform:uppercase}
.tabs{display:flex;margin-bottom:1rem;background:var(--bg-card);border-radius:var(--radius);border:1px solid var(--border);overflow:hidden}
.tab{padding:.45rem .9rem;font-size:.75rem;font-weight:500;color:var(--text-muted);cursor:pointer;border:none;background:none;font-family:inherit;display:flex;align-items:center;gap:.35rem;border-right:1px solid var(--border)}
.tab:last-child{border-right:none}.tab:hover{color:var(--text);background:var(--border-light)}
.tab.active{color:var(--accent);background:rgba(88,166,255,.06);font-weight:600}.tab svg{width:13px;height:13px}
.pane{display:none}.pane.active{display:block}
.filter{display:flex;gap:.3rem;flex-wrap:wrap;margin-bottom:.75rem;align-items:center}
.filter input,.filter select{padding:.3rem .5rem;font-size:.7rem;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);color:var(--text);font-family:inherit}
.filter .btn{padding:.3rem .65rem;font-size:.7rem}
/* DC cards */
.dc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:.5rem}
.dc-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:.75rem;position:relative}
.dc-card::after{content:'';position:absolute;top:0;left:0;right:0;height:3px}
.dc-card.t4::after{background:linear-gradient(90deg,var(--purple),var(--accent))}.dc-card.t3::after{background:linear-gradient(90deg,var(--accent),var(--green))}
.dc-card h3{font-size:.82rem;font-weight:600;color:var(--text)}
.dc-card .dc-loc{font-size:.65rem;color:var(--text-muted);margin:.15rem 0}
.dc-card .dc-row{display:flex;gap:.15rem;flex-wrap:wrap;margin:.2rem 0}
.dc-card .dc-chip{padding:.08rem .3rem;border-radius:3px;font-size:.55rem;font-weight:500}
.dc-chip.blue{background:var(--cyan-bg);color:var(--cyan)}.dc-chip.purple{background:var(--purple-bg);color:var(--purple)}.dc-chip.green{background:var(--green-bg);color:var(--green)}.dc-chip.orange{background:var(--orange-bg);color:var(--orange)}
.dc-card .dc-spec{font-size:.6rem;color:var(--text-dim);margin-top:.25rem;line-height:1.4}
/* Company cards */
.cc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:.5rem}
.cc-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:.8rem;position:relative}
.cc-card::after{content:'';position:absolute;top:0;left:0;right:0;height:3px}
.cc-card.prospect-high::after{background:linear-gradient(90deg,var(--green),var(--accent))}.cc-card.prospect-medium::after{background:linear-gradient(90deg,var(--accent),var(--purple))}.cc-card.prospect-low::after{background:linear-gradient(90deg,var(--text-dim),var(--border))}
.cc-card h3{font-size:.82rem;font-weight:600;color:var(--text)}
.cc-card .cc-sub{font-size:.65rem;color:var(--text-muted);margin:.1rem 0}
.cc-card .cc-chips{display:flex;flex-wrap:wrap;gap:.13rem;margin:.25rem 0}
.cc-card .cc-chip{padding:.08rem .32rem;border-radius:3px;font-size:.55rem;font-weight:500}
.cc-chip.dw{background:var(--purple-bg);color:var(--purple)}.cc-chip.bi{background:var(--cyan-bg);color:var(--cyan)}.cc-chip.cloud{background:var(--green-bg);color:var(--green)}.cc-chip.ai{background:var(--orange-bg);color:var(--orange)}.cc-chip.db{background:var(--pink-bg);color:var(--pink)}
.cc-card .cc-info{font-size:.6rem;color:var(--text-dim);margin-top:.3rem;line-height:1.3}
.cc-card .cc-contact{font-size:.6rem;color:var(--text-dim);margin-top:.3rem}
.cc-card .cc-score{position:absolute;top:.5rem;right:.5rem;padding:.1rem .4rem;border-radius:999px;font-size:.6rem;font-weight:700}
.cc-score.high{background:var(--green-bg);color:var(--green)}.cc-score.medium{background:var(--orange-bg);color:var(--orange)}.cc-score.low{background:var(--border-light);color:var(--text-dim)}
/* Status badges */
.st-badge{padding:.08rem .3rem;border-radius:3px;font-size:.55rem;font-weight:500}
.st-badge.new{background:var(--cyan-bg);color:var(--cyan)}.st-badge.contacted{background:var(--orange-bg);color:var(--orange)}.st-badge.qualified{background:var(--green-bg);color:var(--green)}
</style></head><body>
<nav class="navbar"><div class="nav-inner"><a href="/" class="nav-brand"><img src="/img/logo.svg" class="nav-logo" alt="Mek-Tech"></a><div class="nav-links"><a href="/" class="nav-link">Dashboard</a><a href="/clients" class="nav-link">Cliënten</a><a href="/engagements" class="nav-link">Engagements</a><a href="/finance" class="nav-link">Financiën</a><a href="/market" class="nav-link active">Markt</a><a href="/tasks" class="nav-link">Taken</a><a href="/quality" class="nav-link">Data</a><a href="/settings" class="nav-link">Instellingen</a><a href="/auth/logout" class="nav-link logout">Uitloggen</a></div></div></nav>
<div class="mi-wrap">
<div class="mi-hdr"><h1>🎯 Markt Intelligence</h1><p class="sub">Datacenters & prospects — alle bedrijven met hun tech stack, contactgegevens en lead score</p></div>
<div class="mi-kpi">
<div class="mk"><b><%= datacenters.length %></b><span>datacenters</span></div>
<div class="mk"><b><%= totalPower.toFixed(0) %> MW</b><span>totaal vermogen</span></div>
<div class="mk"><b><%= companies.length %></b><span>tech prospects</span></div>
<div class="mk"><b><%= dwVendors.length %></b><span>DW vendors</span></div>
<div class="mk"><b><%= industries.length %></b><span>sectoren</span></div>
<div class="mk"><b><%= regions.length %></b><span>regio's</span></div>
</div>
<div class="tabs">
<button class="tab <%= tab==='datacenters'?'active':'' %>" onclick="setTab('datacenters')"><i data-lucide="database"></i> Datacenters</button>
<button class="tab <%= tab==='companies'?'active':'' %>" onclick="setTab('companies')"><i data-lucide="building-2"></i> Tech Prospects</button>
</div>
<% var p = tab||'datacenters' %>
<!-- ---- DATACENTERS ---- -->
<div class="pane <%= p==='datacenters'?'active':'' %>" id="pane-datacenters">
<form class="filter" method="GET"><input type="hidden" name="tab" value="datacenters">
<input type="text" name="search" placeholder="Zoek naam, operator, vendor..." value="<%= search %>" style="min-width:180px"><select name="region" onchange="this.form.submit()"><option value="">Alle regio's</option><% regions.forEach(function(r){ %><option value="<%= r %>" <%= region===r?'selected':'' %>><%= r %></option><% }) %></select>
<select name="vendor" onchange="this.form.submit()"><option value="">Alle vendors</option><% allVendors.forEach(function(v){ %><option value="<%= v %>" <%= vendor===v?'selected':'' %>><%= v %></option><% }) %></select>
<button class="btn btn-primary">Filter</button></form>
<div class="dc-grid">
<% datacenters.forEach(function(dc){ %><div class="dc-card <%= dc.tier==='IV'?'t4':'t3' %>">
<h3><%= dc.name %></h3>
<div class="dc-loc"><i data-lucide="map-pin" style="width:10px;height:10px"></i> <%= dc.city %>, <%= dc.region %> · <%= dc.address||'' %></div>
<% if(dc.phone){ %><div class="dc-loc" style="margin-top:1px"><i data-lucide="phone" style="width:10px;height:10px"></i> <%= dc.phone %></div><% } %>
<div class="dc-row"><span class="dc-chip purple">Tier <%= dc.tier %></span><span class="dc-chip blue"><%= dc.type %></span><span class="dc-chip green"><%= dc.operator %></span></div>
<div class="dc-spec"><strong><%= dc.power_mw||0 %> MW</strong> · <%= (dc.size_sqm||0).toLocaleString() %> m²</div>
<% if(dc.network_vendors){ %><div class="dc-spec"><strong>Network:</strong> <%= dc.network_vendors %></div><% } %>
<% if(dc.server_vendors){ %><div class="dc-spec"><strong>Servers:</strong> <%= dc.server_vendors %></div><% } %>
<% if(dc.storage_vendors){ %><div class="dc-spec"><strong>Storage:</strong> <%= dc.storage_vendors %></div><% } %>
<% if(dc.certifications){ %><div class="dc-spec"><strong>Certs:</strong> <%= dc.certifications %></div><% } %>
</div><% }) %>
</div></div>
<!-- ---- COMPANIES ---- -->
<div class="pane <%= p==='companies'?'active':'' %>" id="pane-companies">
<form class="filter" method="GET"><input type="hidden" name="tab" value="companies">
<input type="text" name="search" placeholder="Zoek naam, tech stack, vendor..." value="<%= search %>" style="min-width:180px">
<select name="industry" onchange="this.form.submit()"><option value="">Alle sectoren</option><% industries.forEach(function(i){ %><option value="<%= i %>" <%= industry===i?'selected':'' %>><%= i %></option><% }) %></select>
<select name="dw" onchange="this.form.submit()"><option value="">DW vendor</option><% dwVendors.forEach(function(v){ %><option value="<%= v %>" <%= dw===v?'selected':'' %>><%= v %></option><% }) %></select>
<select name="city" onchange="this.form.submit()"><option value="">Stad</option><% cities.forEach(function(c){ %><option value="<%= c %>" <%= city===c?'selected':'' %>><%= c %></option><% }) %></select>
<select name="sort" onchange="this.form.submit()"><option value="lead_score" <%= sort==='lead_score'?'selected':'' %>>Lead score</option><option value="employees" <%= sort==='employees'?'selected':'' %>>Grootte</option><option value="name" <%= sort==='name'?'selected':'' %>>Naam</option></select>
<button class="btn btn-primary">Filter</button></form>
<div class="cc-grid">
<% companies.forEach(function(c){
var prospectClass = c.lead_score >= 70 ? 'prospect-high' : c.lead_score >= 50 ? 'prospect-medium' : 'prospect-low';
var scoreClass = c.lead_score >= 70 ? 'high' : c.lead_score >= 50 ? 'medium' : 'low';
%>
<div class="cc-card <%= prospectClass %>">
<div class="cc-score <%= scoreClass %>"><%= c.lead_score %></div>
<h3><%= c.name %></h3>
<div class="cc-sub"><%= c.industry %> · <%= c.city %> · ~<%= (c.employees||0).toLocaleString() %> medewerkers</div>
<div class="cc-sub" style="margin-top:0"><%= c.address||'' %> <%= c.postal_code||'' %></div>
<% if(c.phone || c.email || c.website){ %><div class="cc-contact">📞 <%= c.phone||'-' %> · ✉ <%= c.email||'-' %> · 🌐 <%= c.website||'-' %></div><% } %>
<% if(c.data_warehouse){ %><div class="cc-chips"><% c.data_warehouse.split(',').slice(0,6).forEach(function(v){ %><span class="cc-chip dw"><%= v.trim() %></span><% }) %></div><% } %>
<% if(c.bi_tools){ %><div class="cc-chips"><% c.bi_tools.split(',').slice(0,4).forEach(function(v){ %><span class="cc-chip bi"><%= v.trim() %></span><% }) %></div><% } %>
<% if(c.cloud_provider){ %><div class="cc-chips"><% c.cloud_provider.split(',').slice(0,3).forEach(function(v){ %><span class="cc-chip cloud"><%= v.trim() %></span><% }) %></div><% } %>
<% if(c.ai_ml){ %><div class="cc-chips"><% c.ai_ml.split(',').slice(0,3).forEach(function(v){ %><span class="cc-chip ai"><%= v.trim() %></span><% }) %></div><% } %>
<% if(c.database_vendor){ %><div class="cc-chips"><% c.database_vendor.split(',').slice(0,3).forEach(function(v){ %><span class="cc-chip db"><%= v.trim() %></span><% }) %></div><% } %>
<div class="cc-info">Data lake: <%= c.data_lake||'-' %> · Revenue: <%= c.revenue_range||'-' %></div>
</div><% }) %>
</div></div>
</div>
<script>
function setTab(t){
var u=new URL(window.location);u.searchParams.set('tab',t);window.location.href=u.toString();
}
lucide.createIcons();
</script>
</body></html>