// cart.js - Shopping cart
function _cartLoad() {
try { _cartItems = JSON.parse(sessionStorage.getItem('solarCart') || '[]'); } catch(e) { _cartItems = []; }
}
function _cartSave() {
sessionStorage.setItem('solarCart', JSON.stringify(_cartItems));
cartUpdateBadge();
}
function cartAddFromModal() {
if(!_spProduct) return;
const p = _spProduct;
const variants = (p.specs && p.specs.variants) || [];
const sv = variants[_spSelectedVariant] || {};
const rules = (p.specs && p.specs.rules) || [];
const ruleResult = peApplyRules(rules, sv, _spTillval);
// Determine variant label
let variantLabel = '';
if(variants.length > 1) {
const first = variants[0];
if(first.kwh !== undefined) variantLabel = sv.kwh + ' kWh';
else if(first.paneler !== undefined) variantLabel = sv.paneler + ' paneler';
else if(first.cm !== undefined) variantLabel = sv.cm + ' cm';
else if(first.material !== undefined) variantLabel = sv.material;
else variantLabel = Object.values(sv)[0];
}
// Calculate prices
let basePrice = p.price, greenDeduction = 0, isPerUnit = false;
if(variants.length) {
if(sv.totalt !== undefined) { basePrice = parseFloat(sv.totalt) || 0; if(sv.gron_teknik !== undefined) greenDeduction = parseFloat(sv.gron_teknik) || 0; }
else if(sv.pris_per_m2 !== undefined) { basePrice = parseFloat(sv.pris_per_m2) || 0; isPerUnit = true; }
else if(sv.price !== undefined) { basePrice = parseFloat(sv.price) || 0; }
}
if(ruleResult['__product'] && ruleResult['__product'].pris !== null) basePrice = ruleResult['__product'].pris;
let tillvalTotal = 0;
// Window size info
let windowSize = null;
if(p.specs && p.specs.type === 'window_sizes' && _spSelectedWindowSize) {
const winAntal = parseInt(document.getElementById('spWinAntal')?.value) || 1;
const _cr = _currencyRates[p.costCurrency||'EUR'] || _currencyRates['EUR'] || 1;
const _mk = p.markupType==='percent'&&p.markupValue ? (1+p.markupValue/100) : 1;
const _mkA = p.markupType==='amount'&&p.markupValue ? p.markupValue*winAntal : 0;
const eurPrice = _spSelectedWindowSize.price * winAntal;
basePrice = Math.round(eurPrice * _cr * _mk + _mkA);
windowSize = {
w: _spSelectedWindowSize.w,
h: _spSelectedWindowSize.h,
antal: winAntal,
article_id: _spSelectedWindowSize.article_id,
eurPrice: eurPrice,
sekPrice: basePrice
};
variantLabel = (_spSelectedWindowSize.w*10)+'x'+(_spSelectedWindowSize.h*10)+' cm' + (winAntal > 1 ? ' x'+winAntal : '');
}
// Style/width selection for style_width_variants
let styleWidthInfo = null;
if(p.specs && p.specs.type === 'style_width_variants' && _spSelectedWidth !== null) {
const style = p.specs.styles[_spSelectedStyle];
const variant = style && style.variants[_spSelectedWidth];
styleWidthInfo = { style: style?.style, width_mm: variant?.width_mm, price: variant?.price };
variantLabel = (style?.style || '') + ' ' + (variant?.width_mm || '') + ' mm';
}
// Tillval with their selected variants
const tillvalDetailed = _spTillval.filter(tv => tv.checked && !tv.excluded).map(tv => {
let pr = tv.computedPrice !== null ? tv.computedPrice : tv.price;
let selectedStyle = null, selectedWidth = null;
if(tv.specs && tv.selectedVariant !== null && tv.selectedVariant !== undefined) {
if(tv.specs.type === 'style_width_variants') {
const s = tv.specs.styles[tv.selectedStyle];
const v = s && s.variants[tv.selectedVariant];
if(v && v.price != null) pr = v.price;
selectedStyle = s?.style;
selectedWidth = v?.width_mm;
} else if(tv.specs.type === 'width_variants') {
const v = tv.specs.variants[tv.selectedVariant];
if(v && v.price != null) pr = v.price;
selectedWidth = v?.width_mm || v?.length_mm;
}
}
const eq = tv.unit === 'm\u00b2' ? (tv.userL * tv.userW) : (tv.unit && tv.unit !== 'st' && tv.userQty > 0 ? tv.userQty : tv.qty);
const effectiveQty = eq || (tv.unit === 'st' || !tv.unit ? 1 : 0);
const t = pr * effectiveQty;
tillvalTotal += t;
return {
id: tv.id, name: tv.name, price: pr, qty: effectiveQty, total: t,
unit: tv.unit, computedLangd: tv.computedLangd || null, computedBredd: tv.computedBredd || null,
selectedStyle: selectedStyle, selectedWidth: selectedWidth
};
});
// Spröjs
const sprojsLabels = ['Inga','1V, 1H','1V, 2H','2V, 2H'];
const sprojs = { index: _spSelectedSprojs || 0, label: sprojsLabels[_spSelectedSprojs || 0] };
// Färg
const farg = {
insida: _spSelectedColors ? { ..._spSelectedColors.insida } : { name:'Vit', code:'RAL 9010' },
utsida: _spSelectedColors ? { ..._spSelectedColors.utsida } : { name:'Vit', code:'RAL 9010' }
};
const total = basePrice - greenDeduction + tillvalTotal;
_cartItems.push({
productId: p.id,
productName: p.name,
catLabel: p.catLabel,
img: p.img || '',
variantIdx: _spSelectedVariant,
variantLabel: variantLabel,
windowSize: windowSize,
styleWidthInfo: styleWidthInfo,
tillval: tillvalDetailed,
basePrice: basePrice,
greenDeduction: greenDeduction,
tillvalTotal: tillvalTotal,
total: total,
isPerUnit: isPerUnit,
sprojs: sprojs,
farg: farg
});
_cartSave();
cartToast('Tillagd i kalkyl!');
}
function cartRemove(idx) {
_cartItems.splice(idx, 1);
_cartSave();
cartRender();
}
function cartClear() {
_cartItems = [];
_cartSave();
cartRender();
}
function cartUpdateBadge() {
let btn = document.getElementById('cartFloatBtn');
if(!btn) {
btn = document.createElement('div');
btn.id = 'cartFloatBtn';
btn.onclick = () => cartTogglePanel();
btn.style.cssText = 'position:fixed;bottom:24px;right:24px;z-index:9990;background:#024550;color:#fff;border-radius:16px;padding:12px 20px;cursor:pointer;box-shadow:0 8px 24px rgba(2,69,80,.4);display:flex;align-items:center;gap:8px;font-family:Inter,sans-serif;font-size:14px;font-weight:700;transition:transform .2s,opacity .2s;user-select:none';
btn.innerHTML = '<svg viewBox="0 0 24 24" style="width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:2"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg><span id="cartBadgeText">Kalkyl (0)</span>';
document.body.appendChild(btn);
}
const count = _cartItems.length;
document.getElementById('cartBadgeText').textContent = 'Kalkyl (' + count + ')';
btn.style.transform = count > 0 ? 'scale(1)' : 'scale(0)';
btn.style.opacity = count > 0 ? '1' : '0';
btn.style.pointerEvents = count > 0 ? 'auto' : 'none';
}
function cartTogglePanel() {
let panel = document.getElementById('cartPanel');
if(panel) { panel.remove(); return; }
panel = document.createElement('div');
panel.id = 'cartPanel';
panel.style.cssText = 'position:fixed;top:0;right:0;width:400px;max-width:90vw;height:100vh;background:#fff;z-index:9998;box-shadow:-8px 0 32px rgba(0,0,0,.15);display:flex;flex-direction:column;font-family:Inter,sans-serif;animation:cartSlideIn .25s ease-out';
// Add animation keyframe if not exists
if(!document.getElementById('cartAnimStyle')) {
const style = document.createElement('style');
style.id = 'cartAnimStyle';
style.textContent = '@keyframes cartSlideIn{from{transform:translateX(100%)}to{transform:translateX(0)}}';
document.head.appendChild(style);
}
panel.innerHTML = '<div style="padding:16px 20px;border-bottom:1px solid #f1f5f9;display:flex;justify-content:space-between;align-items:center">'
+'<h3 style="margin:0;font-size:16px;font-weight:800;color:#1a1a1a">Kalkyl</h3>'
+'<button onclick="document.getElementById(\'cartPanel\').remove()" style="background:none;border:none;cursor:pointer;color:#94a3b8;font-size:22px;line-height:1;padding:4px">×</button>'
+'</div>'
+'<div id="cartPanelItems" style="flex:1;overflow-y:auto;padding:12px 20px"></div>'
+'<div id="cartPanelFooter" style="padding:16px 20px;border-top:1px solid #f1f5f9"></div>';
document.body.appendChild(panel);
// Backdrop
const backdrop = document.createElement('div');
backdrop.id = 'cartBackdrop';
backdrop.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.3);z-index:9997';
backdrop.onclick = () => { panel.remove(); backdrop.remove(); };
document.body.appendChild(backdrop);
panel._backdrop = backdrop;
const origRemove = panel.remove.bind(panel);
panel.remove = function() { backdrop.remove(); origRemove(); };
cartRender();
}
function cartRender() {
const itemsEl = document.getElementById('cartPanelItems');
const footerEl = document.getElementById('cartPanelFooter');
if(!itemsEl || !footerEl) return;
if(!_cartItems.length) {
itemsEl.innerHTML = '<div style="text-align:center;padding:40px 0;color:#94a3b8"><svg viewBox="0 0 24 24" style="width:40px;height:40px;stroke:currentColor;fill:none;stroke-width:1.5;margin-bottom:8px"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg><div style="font-size:13px">Varukorgen är tom</div><div style="font-size:12px;margin-top:4px">Lägg till produkter från katalogen</div></div>';
footerEl.innerHTML = '';
return;
}
let grandTotal = 0;
itemsEl.innerHTML = _cartItems.map((item, idx) => {
grandTotal += item.total;
const imgTag = item.img ? '<img src="'+item.img+'" style="width:48px;height:48px;object-fit:cover;border-radius:8px;flex-shrink:0">' : '<div style="width:48px;height:48px;background:#f1f5f9;border-radius:8px;flex-shrink:0"></div>';
let details = '';
if(item.variantLabel) details += '<div style="font-size:11px;color:#64748b">'+item.variantLabel+'</div>';
if(item.greenDeduction > 0) details += '<div style="font-size:11px;color:#059669">Grönt teknik: -'+item.greenDeduction.toLocaleString('sv-SE')+' kr</div>';
if(item.tillval && item.tillval.length) {
details += item.tillval.map(tv => '<div style="font-size:11px;color:#64748b">+ '+tv.name+': '+tv.total.toLocaleString('sv-SE')+' kr</div>').join('');
}
return '<div style="display:flex;gap:12px;padding:12px 0;border-bottom:1px solid #f8f9fa">'
+ imgTag
+'<div style="flex:1;min-width:0">'
+'<div style="font-size:13px;font-weight:700;color:#1a1a1a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">'+item.productName+'</div>'
+'<div style="font-size:10px;color:#94a3b8;margin-bottom:2px">'+item.catLabel+'</div>'
+ details
+'<div style="font-size:14px;font-weight:800;color:#024550;margin-top:4px">'+item.total.toLocaleString('sv-SE')+' kr'+(item.isPerUnit?' /m²':'')+'</div>'
+'</div>'
+'<button onclick="cartRemove('+idx+')" style="background:none;border:none;cursor:pointer;color:#dc2626;padding:4px;flex-shrink:0;align-self:flex-start" title="Ta bort"><svg viewBox="0 0 24 24" style="width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg></button>'
+'</div>';
}).join('');
footerEl.innerHTML = '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px">'
+'<span style="font-size:15px;font-weight:700;color:#1a1a1a">Totalt</span>'
+'<span style="font-size:20px;font-weight:800;color:#024550">'+grandTotal.toLocaleString('sv-SE')+' kr</span>'
+'</div>'
+'<button onclick="cartSaveAsQuote()" style="width:100%;padding:12px;background:#024550;color:#fff;border:none;border-radius:10px;font-size:14px;font-weight:700;cursor:pointer;font-family:inherit;margin-bottom:8px">Spara som ny kalkyl</button>'
+'<button onclick="cartAddToExisting()" style="width:100%;padding:10px;background:#f0f9ff;color:#024550;border:1.5px solid #024550;border-radius:10px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit;margin-bottom:8px">Lägg till i befintlig kalkyl</button>'
+'<button onclick="cartClear();cartRender()" style="width:100%;padding:10px;background:#fee2e2;color:#dc2626;border:none;border-radius:10px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit">Rensa varukorg</button>';
}
async function cartSaveAsQuote() {
if(!_cartItems.length) return;
// Bygg modal för namn + kund
var old = document.getElementById('cartSaveModal');
if(old) old.remove();
var modal = document.createElement('div');
modal.id = 'cartSaveModal';
modal.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:100000;display:flex;align-items:center;justify-content:center;padding:20px';
modal.onclick = function(e){ if(e.target===modal) modal.remove(); };
var cats = _cartItems.map(function(i){return i.catLabel;}).filter(function(v,i,a){return a.indexOf(v)===i;});
var defaultName = cats.join(' + ');
var total = _cartItems.reduce(function(s,i){return s+i.total;}, 0);
modal.innerHTML = '<div style="background:#fff;border-radius:14px;padding:24px;max-width:440px;width:100%;box-shadow:0 20px 60px rgba(0,0,0,.2)">'
+'<h3 style="margin:0 0 16px;font-size:17px;font-weight:700">Spara kalkyl</h3>'
+'<div style="margin-bottom:12px"><label style="font-size:12px;font-weight:600;color:#64748b;display:block;margin-bottom:4px">Kalkylnamn</label>'
+'<input type="text" id="cartSaveName" value="'+defaultName+'" style="width:100%;padding:10px 14px;border:1.5px solid #e5e7eb;border-radius:8px;font-size:14px;font-family:inherit;box-sizing:border-box"></div>'
+'<div style="margin-bottom:12px"><label style="font-size:12px;font-weight:600;color:#64748b;display:block;margin-bottom:4px">Kund (valfritt)</label>'
+'<input type="text" id="cartSaveCustomer" placeholder="Kundnamn..." style="width:100%;padding:10px 14px;border:1.5px solid #e5e7eb;border-radius:8px;font-size:14px;font-family:inherit;box-sizing:border-box"></div>'
+'<div style="background:#f8f9fa;border-radius:8px;padding:12px;margin-bottom:16px">'
+'<div style="font-size:12px;color:#64748b;margin-bottom:6px">'+_cartItems.length+' produkt'+ (_cartItems.length>1?'er':'')+'</div>'
+_cartItems.map(function(i){return '<div style="display:flex;justify-content:space-between;font-size:13px;margin-bottom:2px"><span>'+i.productName+'</span><span style="font-weight:600">'+i.total.toLocaleString('sv-SE')+' kr</span></div>';}).join('')
+'<div style="border-top:1px solid #e5e7eb;margin-top:6px;padding-top:6px;display:flex;justify-content:space-between;font-weight:700;font-size:14px"><span>Totalt</span><span style="color:#024550">'+total.toLocaleString('sv-SE')+' kr</span></div>'
+'</div>'
+'<div style="display:flex;gap:8px">'
+'<button onclick="document.getElementById(\'cartSaveModal\').remove()" style="flex:1;padding:12px;border:1.5px solid #e5e7eb;border-radius:10px;background:#fff;cursor:pointer;font-family:inherit;font-size:14px;font-weight:600">Avbryt</button>'
+'<button onclick="doCartSave()" style="flex:1;padding:12px;border:none;border-radius:10px;background:#024550;color:#fff;cursor:pointer;font-family:inherit;font-size:14px;font-weight:700">Spara</button>'
+'</div></div>';
document.body.appendChild(modal);
document.getElementById('cartSaveName').focus();
}
async function doCartSave() {
var name = document.getElementById('cartSaveName').value.trim() || 'Produktkalkyl';
var customer = document.getElementById('cartSaveCustomer').value.trim();
var total = _cartItems.reduce(function(s,i){return s+i.total;}, 0);
var cats = _cartItems.map(function(i){return i.catLabel;}).filter(function(v,i,a){return a.indexOf(v)===i;});
var summary = _cartItems.length + ' produkt' + (_cartItems.length>1?'er':'') + ' — ' + cats.join(', ');
try {
var res = await fetch('/api/quotes.php', {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({
category: 'produktkatalog',
config_data: JSON.stringify({items: _cartItems}),
total_price: total,
deal_total: total,
panel_name: summary,
customer_name: customer || ('Märkning: ' + name),
status: 'utkast',
created_by: gStaffId || null
})
});
var data = await res.json();
if(data.error) { alert('Fel: ' + data.error); return; }
var modal = document.getElementById('cartSaveModal');
if(modal) modal.remove();
cartToast('Kalkyl #' + data.id + ' sparad — ' + name);
_cartItems = [];
_cartSave();
cartRender();
// Navigera till kalkyllistan
navigateTo('konfigurator');
} catch(e) { alert('Fel: ' + e.message); }
}
// Öppna en produktkatalog-kalkyl (varukorgsvy)
// Öppna sparad produktkalkyl
function openProductQuote(quoteData) {
var q = quoteData;
var config = {};
try { config = typeof q.config_data === 'string' ? JSON.parse(q.config_data) : q.config_data; } catch(e){}
var items = config.items || [];
if(!items.length) { alert('Denna kalkyl har inga produkter'); return; }
// Visa kalkylConfigView, dölj lista
document.getElementById('kalkylListView').style.display = 'none';
document.getElementById('kalkylConfigView').style.display = 'block';
// Dölj ALLT i kalkylConfigView
var configView = document.getElementById('kalkylConfigView');
Array.from(configView.children).forEach(function(ch){ ch.style.display = 'none'; });
// Ta bort gammal produktvy
var existingPqv = document.getElementById('productQuoteView');
if(existingPqv) existingPqv.remove();
// Bygg produktlista + prissammanställning i 2-kolumns grid
var pqv = document.createElement('div');
pqv.id = 'productQuoteView';
pqv.style.cssText = 'display:grid;grid-template-columns:1fr 380px;gap:24px;align-items:start';
// Beräkna total
var total = 0;
items.forEach(function(i){ total += i.total || 0; });
// VÄNSTER: Produktlista
var left = '<div>';
left += '<div style="display:flex;align-items:center;gap:12px;margin-bottom:16px"><button onclick="kalkylGoBack()" style="padding:8px 14px;border:1.5px solid #e5e7eb;border-radius:8px;background:#fff;cursor:pointer;font-family:inherit;font-size:13px;font-weight:600;display:flex;align-items:center;gap:4px"><svg viewBox="0 0 24 24" style="width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>Tillbaka</button><h2 style="font-size:18px;font-weight:700;margin:0">' + (q.panel_name || 'Kalkyl') + '</h2></div>';
if(q.customer_name) left += '<div style="font-size:13px;color:#64748b;margin-bottom:12px">' + q.customer_name + '</div>';
items.forEach(function(item, idx) {
var tillvalHtml = '';
if(item.tillval && item.tillval.length) {
tillvalHtml = item.tillval.map(function(tv) {
return '<div style="font-size:12px;color:#64748b;padding-left:12px">+ ' + tv.name + ': ' + (tv.total||tv.price||0).toLocaleString('sv-SE') + ' kr</div>';
}).join('');
}
left += '<div style="background:#fff;border:1px solid #e5e7eb;border-radius:12px;padding:16px;margin-bottom:10px">'
+ '<div style="display:flex;gap:14px;align-items:flex-start">'
+ (item.img ? '<img src="' + item.img + '" style="width:60px;height:60px;object-fit:cover;border-radius:8px;flex-shrink:0">' : '')
+ '<div style="flex:1">'
+ '<div style="font-weight:600;font-size:15px">' + item.productName + '</div>'
+ '<div style="font-size:12px;color:#94a3b8">' + (item.catLabel||'') + (item.variantLabel ? ' — ' + item.variantLabel : '') + '</div>'
+ tillvalHtml
+ '</div>'
+ '<div style="font-size:16px;font-weight:700;color:#024550">' + (item.total||0).toLocaleString('sv-SE') + ' kr</div>'
+ '</div>'
+ '<div style="margin-top:10px;padding-top:10px;border-top:1px solid #f1f5f9;display:flex;gap:8px">'
+ '<button onclick="editQuoteProduct(\'' + item.productId + '\')" style="padding:6px 14px;border:1.5px solid #024550;border-radius:8px;background:#fff;color:#024550;cursor:pointer;font-family:inherit;font-size:12px;font-weight:600">Redigera</button>'
+ '<button onclick="removeQuoteProduct(' + idx + ')" style="padding:6px 14px;border:1.5px solid #fee2e2;border-radius:8px;background:#fff;color:#dc2626;cursor:pointer;font-family:inherit;font-size:12px;font-weight:600">Ta bort</button>'
+ '</div></div>';
});
left += '<div style="margin-top:12px"><button onclick="navigateTo(\'produkter\')" style="padding:10px 20px;border:1.5px dashed #94a3b8;border-radius:10px;background:#fff;color:#64748b;cursor:pointer;font-family:inherit;font-size:13px;font-weight:600;width:100%">+ Lägg till fler produkter</button></div>';
left += '</div>';
// HÖGER: Prissammanställning (samma design som befintliga)
var right = '<div style="position:sticky;top:20px"><div class="price-card" style="background:#fff;border-radius:12px;border:1px solid #e5e7eb;overflow:hidden">'
+ '<div class="price-header" style="background:#024550;color:#fff;padding:14px 18px;font-size:14px;font-weight:700">Prissammanställning</div>'
+ '<div class="price-rows" style="padding:12px 18px">';
items.forEach(function(item) {
right += '<div class="price-line" style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid #f1f5f9"><span style="font-size:13px">' + item.productName + '</span><span style="font-size:13px;font-weight:600">' + (item.basePrice||item.total||0).toLocaleString('sv-SE') + ' kr</span></div>';
if(item.tillval && item.tillval.length) {
item.tillval.forEach(function(tv) {
right += '<div class="price-line" style="display:flex;justify-content:space-between;padding:4px 0 4px 12px;border-bottom:1px solid #f8f9fa"><span style="font-size:12px;color:#64748b">' + tv.name + '</span><span style="font-size:12px;font-weight:600;color:#64748b">' + (tv.total||tv.price||0).toLocaleString('sv-SE') + ' kr</span></div>';
});
}
});
right += '<div class="price-line subtotal" style="display:flex;justify-content:space-between;padding:10px 0 6px;border-top:1px solid #e5e7eb;margin-top:4px"><span style="font-size:13px;font-weight:600">Totalt</span><span style="font-size:13px;font-weight:700">' + total.toLocaleString('sv-SE') + ' kr</span></div>';
right += '</div>';
// Total
right += '<div style="padding:12px 18px;border-top:2px solid #024550;display:flex;justify-content:space-between;align-items:center"><span style="font-size:16px;font-weight:800;color:#024550">Att betala</span><span style="font-size:22px;font-weight:800;color:#024550">' + total.toLocaleString('sv-SE') + ' kr</span></div>';
right += '</div></div>';
pqv.innerHTML = left + right;
configView.appendChild(pqv);
}
// Redigera en produkt från sparad kalkyl — öppnar kalkylkalkylatorn
function editQuoteProduct(productId) {
// Hitta produktens kategori
var prod = (typeof catalogProducts !== 'undefined' ? catalogProducts : []).find(function(p){ return p.id === productId; });
if(!prod) { alert('Produkten hittades inte i katalogen'); return; }
// Rensa produktvy
var pqw = document.getElementById('productQuoteWrapper');
if(pqw) pqw.style.display = 'none';
// Visa rätt konfigurator baserat på kategori
var catMap = {
'solceller': 'solarConfigView',
'batteri': 'batteriConfigView', 'batteri_utbyggnad': 'batteriConfigView',
'laddbox': 'laddboxConfigView',
'taktvatt': 'taktvatConfigView',
'varmepump': 'varmepumpConfigView',
'tak': 'takConfigView',
'isolering': 'isoleringConfigView',
'fonster': 'fonsterConfigView', 'dorrar': 'fonsterConfigView'
};
var viewId = catMap[prod.cat];
if(!viewId) {
// Öppna i produktmodalen om ingen konfigurator finns
if(typeof showProductModal === 'function') showProductModal(productId);
return;
}
// Visa konfiguratorn
var configView = document.getElementById('kalkylConfigView');
var gridWrap = configView.querySelector('div[style*="grid-template-columns:1fr 380px"]');
if(gridWrap) gridWrap.style.display = '';
var catSel = document.getElementById('categorySelect');
if(catSel) { catSel.parentElement.style.display = ''; catSel.value = prod.cat; }
var catGrid = document.getElementById('cfgCategoryGrid'); if(catGrid) catGrid.style.display = 'none';
var catHeader = document.querySelector('.config-header'); if(catHeader) catHeader.style.display = '';
// Dölj alla, visa rätt
['solarConfigView','batteriConfigView','laddboxConfigView','taktvatConfigView','varmepumpConfigView','takConfigView','isoleringConfigView','fonsterConfigView'].forEach(function(v){
var el = document.getElementById(v); if(el) el.style.display = v === viewId ? 'block' : 'none';
});
// Init konfiguratorn
var initMap = {
'batteriConfigView': 'initBatConfig',
'laddboxConfigView': 'initLbConfig',
'taktvatConfigView': 'initTtConfig',
'varmepumpConfigView': 'initVpConfig',
'takConfigView': 'initTakConfig',
'isoleringConfigView': 'initIsoConfig',
'solarConfigView': 'initSolarConfig'
};
var initFn = initMap[viewId];
if(initFn && typeof window[initFn] === 'function') window[initFn]();
}
// Ta bort produkt från sparad kalkyl
function removeQuoteProduct(idx) {
if(typeof cfgRemoveItem === 'function') {
var items = document.querySelectorAll('#productQuoteView > div[style*="border-radius:12px"]');
if(items[idx]) items[idx].remove();
}
// TODO: uppdatera sparad kalkyl i DB
}
// Lägg till varukorgens produkter i en befintlig kalkyl
async function cartAddToExisting() {
if(!_cartItems.length) return;
try {
var res = await fetch('/api/quotes.php?list=1&status=utkast');
var data = await res.json();
var quotes = (data.success ? data.quotes : []) || [];
if(!quotes.length) { alert('Inga befintliga kalkyler att lägga till i. Spara som ny kalkyl istället.'); return; }
var old = document.getElementById('cartExistingModal');
if(old) old.remove();
var modal = document.createElement('div');
modal.id = 'cartExistingModal';
modal.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:100000;display:flex;align-items:center;justify-content:center;padding:20px';
modal.onclick = function(e){ if(e.target===modal) modal.remove(); };
var listHtml = quotes.slice(0,15).map(function(q) {
var label = '#' + q.id + ' — ' + (q.quote_name || q.panel_name || 'Kalkyl');
var kund = q.customer_name || 'Ej angiven';
var pris = q.total_price ? parseInt(q.total_price).toLocaleString('sv-SE') + ' kr' : '0 kr';
return '<div onclick="doCartAddToQuote(' + q.id + ')" style="padding:12px 14px;border:1px solid #e5e7eb;border-radius:8px;cursor:pointer;display:flex;justify-content:space-between;align-items:center;transition:all .1s" onmouseover="this.style.background=\'#f0f9ff\';this.style.borderColor=\'#3b82f6\'" onmouseout="this.style.background=\'#fff\';this.style.borderColor=\'#e5e7eb\'">'
+ '<div><div style="font-weight:600;font-size:14px">' + label + '</div><div style="font-size:12px;color:#64748b">' + kund + '</div></div>'
+ '<div style="font-weight:700;font-size:14px;color:#024550">' + pris + '</div></div>';
}).join('');
modal.innerHTML = '<div style="background:#fff;border-radius:14px;padding:24px;max-width:500px;width:100%;max-height:80vh;overflow-y:auto;box-shadow:0 20px 60px rgba(0,0,0,.2)">'
+ '<h3 style="margin:0 0 16px;font-size:17px;font-weight:700">Lägg till i befintlig kalkyl</h3>'
+ '<div style="display:flex;flex-direction:column;gap:6px">' + listHtml + '</div>'
+ '<button onclick="document.getElementById(\'cartExistingModal\').remove()" style="width:100%;margin-top:12px;padding:10px;border:1.5px solid #e5e7eb;border-radius:10px;background:#fff;cursor:pointer;font-family:inherit;font-size:13px;font-weight:600">Avbryt</button>'
+ '</div>';
document.body.appendChild(modal);
} catch(e) { alert('Fel: ' + e.message); }
}
async function doCartAddToQuote(quoteId) {
try {
// Hämta befintlig kalkyldata
var res = await fetch('/api/quotes.php?id=' + quoteId);
var data = await res.json();
if(!data.success || !data.quote) { alert('Kunde inte ladda kalkylen'); return; }
var q = data.quote;
var config = {};
try { config = typeof q.config_data === 'string' ? JSON.parse(q.config_data) : q.config_data; } catch(e){}
var existingItems = config.items || [];
// Slå ihop befintliga + nya
var allItems = existingItems.concat(_cartItems);
var newTotal = allItems.reduce(function(s,i){ return s + (i.total||0); }, 0);
var cats = allItems.map(function(i){return i.catLabel;}).filter(function(v,i,a){return a.indexOf(v)===i;});
var summary = allItems.length + ' produkt' + (allItems.length>1?'er':'') + ' — ' + cats.join(', ');
// Uppdatera kalkylen
var saveRes = await fetch('/api/quotes.php', {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({
id: quoteId,
config_data: JSON.stringify({items: allItems}),
total_price: newTotal,
deal_total: newTotal,
panel_name: summary
})
});
var saveData = await saveRes.json();
if(saveData.error) { alert('Fel: ' + saveData.error); return; }
var modal = document.getElementById('cartExistingModal');
if(modal) modal.remove();
cartToast(_cartItems.length + ' produkt' + (_cartItems.length>1?'er':'') + ' tillagda i kalkyl #' + quoteId);
_cartItems = [];
_cartSave();
cartRender();
} catch(e) { alert('Fel: ' + e.message); }
}
function cartToast(msg) {
const t = document.createElement('div');
t.style.cssText = 'position:fixed;bottom:80px;right:24px;z-index:100000;background:#024550;color:#fff;padding:12px 20px;border-radius:10px;font-size:13px;font-weight:600;font-family:Inter,sans-serif;box-shadow:0 8px 24px rgba(0,0,0,.2);animation:cartSlideIn .2s ease-out;display:flex;align-items:center;gap:8px';
t.innerHTML = '<svg viewBox="0 0 24 24" style="width:18px;height:18px;stroke:#10b981;fill:none;stroke-width:2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>' + msg;
document.body.appendChild(t);
setTimeout(() => { t.style.opacity = '0'; t.style.transition = 'opacity .3s'; setTimeout(() => t.remove(), 300); }, 2500);
}
// Init cart on page load
_cartLoad();
setTimeout(cartUpdateBadge, 500);
function spOpenFullscreen() {
if(!_spImages.length) return;
const ov = document.createElement('div');
ov.style.cssText = 'position:fixed;inset:0;z-index:100000;background:rgba(0,0,0,.92);display:flex;align-items:center;justify-content:center';
let fsIdx = _spCurrentImage;
const render = () => { ov.querySelector('img').src = _spImages[fsIdx]; };
ov.innerHTML = '<button onclick="this.parentElement.remove()" style="position:absolute;top:20px;right:20px;background:rgba(255,255,255,.15);border:none;color:#fff;width:40px;height:40px;border-radius:50%;font-size:22px;cursor:pointer;z-index:1">×</button>'
+(_spImages.length > 1 ? '<button id="spFsPrev" style="position:absolute;left:20px;top:50%;transform:translateY(-50%);background:rgba(255,255,255,.15);border:none;color:#fff;width:44px;height:44px;border-radius:50%;font-size:22px;cursor:pointer;z-index:1"><svg viewBox="0 0 24 24" style="width:24px;height:24px;stroke:currentColor;fill:none;stroke-width:2"><polyline points="15 18 9 12 15 6"/></svg></button>' : '')
+'<img src="'+_spImages[fsIdx]+'" style="max-width:90vw;max-height:90vh;object-fit:contain;border-radius:8px">'
+(_spImages.length > 1 ? '<button id="spFsNext" style="position:absolute;right:20px;top:50%;transform:translateY(-50%);background:rgba(255,255,255,.15);border:none;color:#fff;width:44px;height:44px;border-radius:50%;font-size:22px;cursor:pointer;z-index:1"><svg viewBox="0 0 24 24" style="width:24px;height:24px;stroke:currentColor;fill:none;stroke-width:2"><polyline points="9 18 15 12 9 6"/></svg></button>' : '');
document.body.appendChild(ov);
if(_spImages.length > 1) {
ov.querySelector('#spFsPrev').onclick = e => { e.stopPropagation(); fsIdx = (fsIdx - 1 + _spImages.length) % _spImages.length; render(); };
ov.querySelector('#spFsNext').onclick = e => { e.stopPropagation(); fsIdx = (fsIdx + 1) % _spImages.length; render(); };
}
ov.addEventListener('keydown', e => { if(e.key==='Escape') ov.remove(); if(e.key==='ArrowLeft'&&_spImages.length>1){fsIdx=(fsIdx-1+_spImages.length)%_spImages.length;render();} if(e.key==='ArrowRight'&&_spImages.length>1){fsIdx=(fsIdx+1)%_spImages.length;render();} });
ov.tabIndex = 0; ov.focus();
}