// dashboard.js - Dashboard + charts
async function loadDashboard() {
try {
// Load deal stats
const [statsR, dealsR, custR] = await Promise.all([
fetch('api/deals.php?action=stats&t='+Date.now()),
fetch('api/deals.php?limit=5&status_exclude=anger,ej_godkand,avbrott&t='+Date.now()),
fetch('api/customers.php?limit=1&t='+Date.now())
]);
const stats = await statsR.json();
const dealsData = await dealsR.json();
const custData = await custR.json();
const el = (id,v) => { const e=document.getElementById(id); if(e) e.textContent=v; };
// Total value (all active deals)
let totalVal = 0, offertCount = 0, acceptedCount = 0;
Object.entries(stats).forEach(([k,v]) => {
totalVal += v.value || 0;
if (k === 'offert') offertCount = v.count || 0;
if (['order','projektering','bestallning','leverans','montering','besiktning','fardigstall'].includes(k)) acceptedCount += v.count || 0;
});
el('dashTotalValue', fmtKr(totalVal));
el('dashOffertar', offertCount);
el('dashKunder', custData.total || 0);
el('dashAccepted', acceptedCount);
// Recent deals
const container = document.getElementById('dashRecentDeals');
if (container && dealsData.deals) {
if (!dealsData.deals.length) {
container.innerHTML = '<div style="padding:20px;text-align:center;color:#94a3b8;font-size:13px">Inga affärer ännu</div>';
} else {
container.innerHTML = dealsData.deals.map(d => {
const products = (d.product_types||'').split(',').filter(Boolean).map(p => PRODUCT_LABELS[p]||p).join(', ');
const color = DEAL_STATUS_COLORS[d.status]||'#94a3b8';
const val = d.ordervarde_ink_moms ? Math.round(parseFloat(d.ordervarde_ink_moms)).toLocaleString('sv-SE')+' kr' : '-';
return '<div class="offert-item" style="cursor:pointer" onclick="showPage(\'projekt\');setTimeout(()=>showDealDetail('+d.id+'),200)">'
+'<div class="offert-item-left"><h4>'+d.customer_name+'</h4><p>'+(products||d.deal_number)+' • '+(d.datum_salj||'')+'</p></div>'
+'<div class="offert-item-right"><div class="offert-price">'+val+'</div><div class="offert-status" style="color:'+color+'">'+DEAL_STATUS_LABELS[d.status]+'</div></div>'
+'</div>';
}).join('');
}
}
// Top sellers
const tsContainer = document.getElementById('dashTopSellers');
if (tsContainer) {
try {
const tsR = await fetch('api/deals.php?action=top_sellers&t='+Date.now());
const sellers = await tsR.json();
if (sellers.length) {
const medals = ['medal-gold','medal-silver','medal-bronze'];
tsContainer.innerHTML = sellers.slice(0,5).map((s,i) =>
'<div class="top-seller-item">'
+(i<3?'<div class="top-seller-medal '+medals[i]+'">'+(i+1)+'</div>':'<div style="width:28px;height:28px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#94a3b8">'+(i+1)+'</div>')
+'<div class="top-seller-info"><div class="top-seller-name">'+s.name+'</div><div class="top-seller-detail">'+s.deal_count+' order</div></div>'
+'<div class="top-seller-amount">'+fmtKr(s.total_value)+'</div>'
+'</div>'
).join('');
} else {
tsContainer.innerHTML = '<div style="padding:20px;text-align:center;color:#94a3b8;font-size:13px">Ingen data</div>';
}
} catch(e) { tsContainer.innerHTML = '<div style="padding:20px;text-align:center;color:#94a3b8;font-size:13px">-</div>'; }
}
} catch(e) { console.error('loadDashboard error:', e); }
}
function fmtKr(n){return n?Math.round(n).toLocaleString('sv-SE')+' kr':'-'}
/* === KUNDER (DataTable) === */
let customerDT = null;
let customersLoaded = false;
let allCustData = [];
/* === DASHBOARD CHARTS === */
function initDashCharts(){
const ctxM=document.getElementById('chartMonthly');
const ctxY=document.getElementById('chartYearly');
if(!ctxM||!ctxY)return;
new Chart(ctxM,{
type:'bar',
data:{
labels:['V6','V7','V8','V9'],
datasets:[
{label:'Order',data:[185000,92500,248000,134200],backgroundColor:'#10b981',borderRadius:4},
{label:'Offerter',data:[87200,53400,96800,42500],backgroundColor:'#eab308',borderRadius:4},
{label:'Förlorade',data:[0,156000,0,73200],backgroundColor:'#ef4444',borderRadius:4}
]
},
options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{position:'bottom',labels:{usePointStyle:true,padding:12,font:{family:'Inter',size:11}}}},scales:{y:{beginAtZero:true,ticks:{callback:v=>v>=1000?(v/1000)+'k':''+v,font:{family:'Inter',size:11}},grid:{color:'#f1f5f9'}},x:{grid:{display:false},ticks:{font:{family:'Inter',size:11}}}}}
});
new Chart(ctxY,{
type:'line',
data:{
labels:['Jan','Feb','Mar','Apr','Maj','Jun','Jul','Aug','Sep','Okt','Nov','Dec'],
datasets:[
{label:'Försäljning',data:[420000,659700,null,null,null,null,null,null,null,null,null,null],borderColor:'#024550',backgroundColor:'rgba(2,69,80,.08)',fill:true,tension:.3,pointRadius:5,pointBackgroundColor:'#024550'},
{label:'Mål',data:[500000,500000,550000,550000,600000,650000,400000,450000,600000,650000,700000,750000],borderColor:'#e5e7eb',borderDash:[5,5],fill:false,tension:.3,pointRadius:0}
]
},
options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{position:'bottom',labels:{usePointStyle:true,padding:12,font:{family:'Inter',size:11}}}},scales:{y:{beginAtZero:true,ticks:{callback:v=>v>=1000?(v/1000)+'k':''+v,font:{family:'Inter',size:11}},grid:{color:'#f1f5f9'}},x:{grid:{display:false},ticks:{font:{family:'Inter',size:11}}}}}
});
}