backups/tillval-qty-20260420_142852/js/cart.js

Code: DEV-17B48F23 Size: 33.6 KB Lines: 562 Path: /home/prodconfig.wenesthosting.com/dev.solargroup.wenest.se/backups/tillval-qty-20260420_142852/js/cart.js

Task / Comment

Open report form
// 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">&times;</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">&times;</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();
}