async function loadUEPage() {
try {
var r = await fetch('api/deals.php?action=contractors&t='+Date.now());
_ueData = await r.json();
var specs = {};
_ueData.forEach(function(c){ if(c.specialty) specs[c.specialty] = (specs[c.specialty]||0)+1; });
var specSel = document.getElementById('ueSpecFilter');
if (specSel) {
specSel.innerHTML = '<option value="">Alla specialiteter</option>' + Object.keys(specs).sort().map(function(s){ return '<option value="'+s+'">'+s+' ('+specs[s]+')</option>'; }).join('');
}
var totalContacts = _ueData.reduce(function(a,c){ return a+c.contacts.length; },0);
var totalActive = _ueData.reduce(function(a,c){ return a+(c.stats?c.stats.active_projects:0); },0);
var cntEl = document.getElementById('ueCount');
if(cntEl) cntEl.textContent = '('+_ueData.length+' f\u00f6retag, '+totalContacts+' kontakter, '+totalActive+' p\u00e5g\u00e5ende projekt)';
filterUE();
} catch(e) { console.error('loadUEPage error:', e); }
}
function filterUE() {
if(!_ueData) return;
var search = (document.getElementById('ueSearch')||{}).value||'';
search = search.toLowerCase();
var spec = (document.getElementById('ueSpecFilter')||{}).value||'';
var filtered = _ueData.filter(function(c){
if(spec && c.specialty !== spec) return false;
if(!search) return true;
if(c.name.toLowerCase().indexOf(search) >= 0) return true;
if((c.specialty||'').toLowerCase().indexOf(search) >= 0) return true;
return c.contacts.some(function(ct){
return (ct.contact_name||'').toLowerCase().indexOf(search) >= 0
|| (ct.phone||'').indexOf(search) >= 0
|| (ct.email||'').toLowerCase().indexOf(search) >= 0;
});
});
renderUECards(filtered);
}
function renderUECards(companies) {
var container = document.getElementById('ueContainer');
if(!container) return;
if(!companies.length) { container.innerHTML = '<div style="text-align:center;color:#94a3b8;padding:40px;font-size:14px">Inga entrepren\u00f6rer hittades</div>'; return; }
container.innerHTML = '<div style="display:flex;flex-direction:column;gap:12px">'
+ companies.map(function(c, idx){
var specColor = '#64748b';
if((c.specialty||'').indexOf('elektriker')>=0) specColor = '#eab308';
else if((c.specialty||'').indexOf('tak')>=0 || (c.specialty||'').indexOf('sol')>=0) specColor = '#f97316';
else if((c.specialty||'').indexOf('f\u00f6nster')>=0) specColor = '#3b82f6';
else if((c.specialty||'').indexOf('pl\u00e5t')>=0) specColor = '#6b7280';
else if((c.specialty||'').indexOf('st\u00e4llning')>=0) specColor = '#8b5cf6';
var st = c.stats || {};
var hasProjects = st.total_projects > 0;
var safeName = c.name.replace(/'/g,"\\'").replace(/"/g,'"');
return '<div id="ue-card-'+idx+'" style="background:#fff;border-radius:12px;border:1px solid #e5e7eb;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,.06)">'
// Header - klickbar
+'<div style="padding:14px 20px;display:flex;align-items:center;justify-content:space-between;cursor:pointer" onclick="toggleUECard('+idx+',\''+safeName+'\')">'
+'<div style="flex:1;min-width:0">'
+'<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">'
+'<div style="width:40px;height:40px;border-radius:10px;background:'+specColor+'15;color:'+specColor+';display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:800;flex-shrink:0">'+c.name.charAt(0)+'</div>'
+'<div>'
+'<div style="font-size:16px;font-weight:700;color:#1a1a1a">'+c.name+'</div>'
+'<div style="display:flex;align-items:center;gap:8px;margin-top:2px">'
+(c.specialty?'<span style="font-size:11px;font-weight:600;padding:2px 10px;border-radius:10px;background:'+specColor+'15;color:'+specColor+';border:1px solid '+specColor+'30">'+c.specialty+'</span>':'')
+'<span style="font-size:11px;color:#64748b">'+c.contacts.length+' kontakter</span>'
+'</div></div></div>'
+'<div style="display:flex;align-items:center;gap:8px">'
+(hasProjects?'<span style="font-size:11px;font-weight:700;padding:3px 10px;border-radius:10px;background:#16a34a;color:#fff">'+st.active_projects+' p\u00e5g\u00e5ende</span>':'')
+(hasProjects?'<span style="font-size:10px;color:#64748b">'+st.total_projects+' tot \u00b7 '+st.completed_projects+' klara \u00b7 '+st.cancelled_projects+' avbr</span>':'<span style="font-size:10px;color:#94a3b8">Inga projekt</span>')
+'</div></div>'
+'<svg id="ue-arrow-'+idx+'" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="2" style="flex-shrink:0;transition:transform .2s"><polyline points="6 9 12 15 18 9"/></svg>'
+'</div>'
// Expanderbar body
+'<div id="ue-body-'+idx+'" style="max-height:0;overflow:hidden;transition:max-height .4s ease">'
+'<div style="border-top:1px solid #e5e7eb">'
// Kontakter
+'<div style="padding:12px 20px">'
+'<div style="font-size:12px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px">Kontakter</div>'
+'<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:8px">'
+ c.contacts.map(function(ct){
return '<div style="display:flex;align-items:center;gap:10px;padding:8px 12px;background:#f8f9fa;border-radius:8px">'
+'<div style="width:32px;height:32px;border-radius:50%;background:#e2e8f0;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;color:#64748b;flex-shrink:0">'+((ct.contact_name||'?').charAt(0))+'</div>'
+'<div style="flex:1;min-width:0">'
+'<div style="font-size:13px;font-weight:600;color:#334155">'+(ct.contact_name||'Ok\u00e4nd')+'</div>'
+(ct.contact_title?'<div style="font-size:11px;color:#94a3b8">'+ct.contact_title+'</div>':'')
+'</div>'
+'<div style="display:flex;gap:4px;flex-shrink:0">'
+(ct.phone?'<a href="tel:'+ct.phone+'" onclick="event.stopPropagation()" style="display:flex;align-items:center;gap:3px;padding:3px 8px;border-radius:6px;background:#f0fdf4;color:#16a34a;text-decoration:none;font-size:11px;font-weight:600;border:1px solid #86efac"><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92z"/></svg>'+ct.phone+'</a>':'')
+(ct.email?'<a href="mailto:'+ct.email+'" onclick="event.stopPropagation()" style="display:flex;align-items:center;gap:3px;padding:3px 8px;border-radius:6px;background:#eff6ff;color:#3b82f6;text-decoration:none;font-size:11px;font-weight:600;border:1px solid #93c5fd"><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>'+ct.email+'</a>':'')
+'</div></div>';
}).join('')
+'</div></div>'
// Projekt-sektion (laddas vid expand)
+'<div id="ue-projects-'+idx+'" style="padding:0 20px 16px">'
+'<div style="text-align:center;padding:20px;color:#94a3b8;font-size:13px">Laddar projekt...</div>'
+'</div>'
+'</div></div></div>';
}).join('')
+'</div>';
}
var _ueExpandedProjects = {};
async function toggleUECard(idx, ueName) {
var body = document.getElementById('ue-body-'+idx);
var arrow = document.getElementById('ue-arrow-'+idx);
if (!body) return;
var isOpen = body.style.maxHeight && body.style.maxHeight !== '0px';
if (isOpen) {
body.style.maxHeight = '0px';
if(arrow) arrow.style.transform = 'rotate(0deg)';
} else {
body.style.maxHeight = '2000px';
if(arrow) arrow.style.transform = 'rotate(180deg)';
// Ladda projekt om inte redan laddat
if (!_ueExpandedProjects[ueName]) {
_ueExpandedProjects[ueName] = true;
loadUECardProjects(idx, ueName);
}
}
}
async function loadUECardProjects(idx, ueName) {
var container = document.getElementById('ue-projects-'+idx);
if (!container) return;
try {
var r = await fetch('api/deals.php?action=ue_projects&ue='+encodeURIComponent(ueName)+'&t='+Date.now());
var projects = await r.json();
if (projects.error) { container.innerHTML = '<div style="color:#ef4444;padding:8px;font-size:13px">'+projects.error+'</div>'; return; }
if (!projects.length) { container.innerHTML = '<div style="padding:12px 0;color:#94a3b8;font-size:13px">Inga projekt hittade f\u00f6r denna UE</div>'; return; }
var activeStatuses = ['Att best\u00e4lla','Att boka','Att projektera','Bokat','Leveransbevakning','Ny order','Projektering bokad','P\u00e5g\u00e5ende','Support / Fels\u00f6kning'];
var active = projects.filter(function(p){ return activeStatuses.indexOf(p.group_title)>=0; });
var completed = projects.filter(function(p){ return p.group_title==='F\u00e4rdigst\u00e4llt'; });
var cancelled = projects.filter(function(p){ return ['Avbrott','Avbrott f\u00e4rdigst\u00e4llt','Avbrott ny order / projektering','\u00c5nger'].indexOf(p.group_title)>=0; });
var other = projects.filter(function(p){ return active.indexOf(p)<0 && completed.indexOf(p)<0 && cancelled.indexOf(p)<0; });
if(other.length) active = active.concat(other);
function statusColor(gt) {
if(activeStatuses.indexOf(gt)>=0) return '#16a34a';
if(gt==='F\u00e4rdigst\u00e4llt') return '#3b82f6';
return '#ef4444';
}
function projSection(rows, label, color, defaultOpen) {
if(!rows.length) return '';
var totalVal = rows.reduce(function(a,p){ return a+parseFloat(p.ordervarde_ink_moms||0); },0);
return '<div style="margin-bottom:12px">'
+'<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;cursor:pointer" onclick="var t=this.nextElementSibling;t.style.display=t.style.display===\'none\'?\'block\':\'none\';this.querySelector(\'svg\').style.transform=t.style.display===\'none\'?\'rotate(-90deg)\':\'rotate(0deg)\'">'
+'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="'+color+'" stroke-width="2.5" style="transition:transform .2s;transform:'+(defaultOpen?'rotate(0deg)':'rotate(-90deg)')+'"><polyline points="6 9 12 15 18 9"/></svg>'
+'<span style="font-size:12px;font-weight:700;color:'+color+'">'+label+'</span>'
+'<span style="font-size:11px;font-weight:600;background:'+color+';color:#fff;padding:1px 8px;border-radius:10px">'+rows.length+'</span>'
+(totalVal?'<span style="font-size:11px;color:#64748b;margin-left:auto">'+fmtKr(totalVal)+'</span>':'')
+'</div>'
+'<div style="display:'+(defaultOpen?'block':'none')+'">'
+'<table style="width:100%;border-collapse:collapse;font-size:12px"><thead><tr style="background:#f8f9fa">'
+'<th style="padding:6px 8px;text-align:left;border-bottom:1px solid #e5e7eb;font-weight:600;color:#64748b">Aff\u00e4rsnr</th>'
+'<th style="padding:6px 8px;text-align:left;border-bottom:1px solid #e5e7eb;font-weight:600;color:#64748b">Kund</th>'
+'<th style="padding:6px 8px;text-align:left;border-bottom:1px solid #e5e7eb;font-weight:600;color:#64748b">Adress</th>'
+'<th style="padding:6px 8px;text-align:left;border-bottom:1px solid #e5e7eb;font-weight:600;color:#64748b">Status</th>'
+'<th style="padding:6px 8px;text-align:right;border-bottom:1px solid #e5e7eb;font-weight:600;color:#64748b">Orderv\u00e4rde</th>'
+'<th style="padding:6px 8px;text-align:left;border-bottom:1px solid #e5e7eb;font-weight:600;color:#64748b">Region</th>'
+'<th style="padding:6px 8px;text-align:left;border-bottom:1px solid #e5e7eb;font-weight:600;color:#64748b">Datum</th>'
+'</tr></thead><tbody>'
+rows.map(function(p){
var sc = statusColor(p.group_title);
return '<tr style="cursor:pointer;transition:background .1s" onmouseover="this.style.background=\'#f8fafc\'" onmouseout="this.style.background=\'#fff\'" onclick="'+(p.deal_id?'showDealDetail('+p.deal_id+')':'')+'">'
+'<td style="padding:6px 8px;font-weight:600;color:#024550;border-bottom:1px solid #f1f5f9">'+(p.deal_number||'-')+'</td>'
+'<td style="padding:6px 8px;border-bottom:1px solid #f1f5f9">'+(p.customer_name||'-')+'</td>'
+'<td style="padding:6px 8px;border-bottom:1px solid #f1f5f9;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+(p.property_address||'-')+'</td>'
+'<td style="padding:6px 8px;border-bottom:1px solid #f1f5f9"><span style="font-size:10px;padding:2px 8px;border-radius:8px;color:#fff;background:'+sc+';white-space:nowrap">'+(p.group_title||'-')+'</span></td>'
+'<td style="padding:6px 8px;text-align:right;border-bottom:1px solid #f1f5f9;font-weight:600">'+(p.ordervarde_ink_moms?fmtKr(parseFloat(p.ordervarde_ink_moms)):'-')+'</td>'
+'<td style="padding:6px 8px;border-bottom:1px solid #f1f5f9">'+(p.region||'-')+'</td>'
+'<td style="padding:6px 8px;border-bottom:1px solid #f1f5f9;color:#64748b">'+(p.datum_salj||'-')+'</td>'
+'</tr>';
}).join('')
+'</tbody></table></div></div>';
}
container.innerHTML = '<div style="font-size:12px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.5px;margin-bottom:10px;padding-top:4px;border-top:1px solid #f1f5f9">Projekt ('+projects.length+')</div>'
+ projSection(active, 'P\u00e5g\u00e5ende', '#16a34a', true)
+ projSection(completed, 'F\u00e4rdigst\u00e4llda', '#3b82f6', false)
+ projSection(cancelled, 'Avbrutna', '#ef4444', false);
// Uppdatera max-height efter innehåll laddats
var body = document.getElementById('ue-body-'+idx);
if(body) body.style.maxHeight = body.scrollHeight + 'px';
} catch(e) {
container.innerHTML = '<div style="color:#ef4444;padding:8px;font-size:13px">Fel vid laddning: '+e.message+'</div>';
}
}
// ============ INKÖP & LEVERANTÖRER ============