js/app.js.bak_20260429_123658_imperdef

Code: DEV-823F54B7 Size: 11.9 KB Lines: 244 Path: /home/prodconfig.wenesthosting.com/dev.solargroup.wenest.se/js/app.js.bak_20260429_123658_imperdef

Task / Comment

Open report form
// app.js - Globals, navigation, helpers

var STAFF_API = '/api/staff.php';
var roleLabels = {systemadmin:'Systemadmin',admin:'Admin',saljchef:'Säljchef',saljare:'Säljare',installator:'Installatör',projektledare:'Projektledare',ekonomi:'Ekonomi',pending:'Pending'};
var roleColors = {systemadmin:'purple',admin:'purple',saljchef:'green',saljare:'green',installator:'blue',projektledare:'yellow',ekonomi:'gray',pending:'gray'};
// === GLOBAL VARS (must be at top to avoid TDZ) ===
var gAccessToken = sessionStorage.getItem('gAccessToken') || '';
var gTokenExpiry = parseInt(sessionStorage.getItem('gTokenExpiry') || '0');
var gStaffId = parseInt(sessionStorage.getItem('gStaffId') || '0');
var gUserEmail = sessionStorage.getItem('gUserEmail') || '';
var gUserName = sessionStorage.getItem('gUserName') || '';
var gUserAvatar = sessionStorage.getItem('gUserAvatar') || '';
var gMailSignature = localStorage.getItem('mailSignature') || '';

function isTabletSidebarMode(){
    return window.innerWidth >= 768 && window.innerWidth <= 1366;
}

function syncSidebarCollapse(){
    const collapse = localStorage.getItem('sidebarCollapsed') === '1';
    if(isTabletSidebarMode()){
        document.body.classList.toggle('sidebar-collapsed', collapse);
    } else {
        document.body.classList.remove('sidebar-collapsed');
    }
}

function toggleSidebarCollapse(forceState){
    const next = typeof forceState === 'boolean'
        ? forceState
        : !(localStorage.getItem('sidebarCollapsed') === '1');
    localStorage.setItem('sidebarCollapsed', next ? '1' : '0');
    syncSidebarCollapse();
}

function showPage(p){ navigateTo(p); }
var currentPage = 'dashboard';
function navigateTo(page){
    if(page === 'minlon') page = 'my-salary';
    if(page === 'profil') page = 'profile';
    if(page === 'configurator-builder') page = 'calc-builder';
    currentPage = page;
    var navPage = page === 'calc-builder' ? 'konfigurator' : page;
    document.querySelectorAll('.nav-item').forEach(n=>n.classList.remove('active'));
    document.querySelectorAll('.nav-item[data-page="'+navPage+'"]').forEach(n=>n.classList.add('active'));
    document.querySelectorAll('.page-content').forEach(p=>{ p.classList.remove('active'); p.style.display = ''; });
    // Stäng Calc_summary-state om vi lämnar sidan (rensar origin så nästa open startar rent)
    if (page !== 'calc-summary' && typeof _calcSummaryOrigin !== 'undefined') { try{ _calcSummaryOrigin = null; }catch(e){} }
    const el = document.getElementById('page-'+page);
    if(el) el.classList.add('active');
    // Update mobile nav
    document.querySelectorAll('.mobile-nav a').forEach(a=>{
        a.classList.toggle('active', a.dataset.page===page);
    });
    if(page === 'admin') initAdminPage();
    if(page === 'settings') try{loadTaxSettingsUI();}catch(e){}
    if(page === 'personal') try{loadStaff();}catch(e){}
    if(page === 'ue') try{loadUEPage();}catch(e){}
    if(page === 'faltsalj'){
        var _tryMap = function(retries){
            if(typeof google !== 'undefined' && google.maps) {
                initFaltMap();
                if(gMap) {
                    // Dubbel-resize + recenter tvingar Google Maps att räkna om container-storleken korrekt
                    // när sidan just blev synlig (innan dess var page-content display:none → 0×0).
                    var c = gMap.getCenter();
                    google.maps.event.trigger(gMap, 'resize');
                    if (c) gMap.setCenter(c);
                    setTimeout(function(){ google.maps.event.trigger(gMap, 'resize'); if (c) gMap.setCenter(c); }, 100);
                }
            } else if(retries > 0) {
                setTimeout(function(){ _tryMap(retries-1); }, 500);
            }
        };
        setTimeout(function(){ _tryMap(10); }, 200);
    }
    if(page === 'inkop') try{loadInkopPage();}catch(e){}
    if(page === 'leverantorer') try{loadLeverantorerPage();}catch(e){}
    if(page === 'inkorg') try{if(typeof updateAuthUI==='function') updateAuthUI(); if(gAccessToken){loadGmailLabels();loadGmailInbox();}}catch(e){}
    if(page === 'kalender') try{if(typeof updateAuthUI==='function') updateAuthUI(); if(gAccessToken){loadCalendarEvents();} setTimeout(function(){if(typeof renderCalendar==='function')renderCalendar();},50);}catch(e){}
    if(page === 'my-salary') try{if(typeof initMySalary==='function') initMySalary();}catch(e){}
    if(page === 'profile') try{if(typeof initProfilePage==='function') initProfilePage(); if(typeof applyProfileMenuPreferences==='function') applyProfileMenuPreferences();}catch(e){}
    if(page === 'konfigurator') try{showKalkylList();}catch(e){}
    if(page === 'calc-builder') try{if(typeof CalcBuilder !== 'undefined' && typeof CalcBuilder.init === 'function') CalcBuilder.init();}catch(e){}
    if(page === 'projekt') try{loadDeals();}catch(e){}
    if(page === 'projektering') try{loadDealPipeline();}catch(e){}
    if(page === 'leads') try{ if(typeof renderLeadsPage==='function') renderLeadsPage(true); }catch(e){}
    if(page === 'kunder') try{loadCustomers();}catch(e){}
    if(page === 'oversikt') try{if(typeof loadDashboard==='function')loadDashboard();}catch(e){}
}
document.querySelectorAll('.nav-item').forEach(item=>{
    item.addEventListener('click',function(){
        navigateTo(this.dataset.page);
    });
});
document.querySelectorAll('.mobile-nav a').forEach(item=>{
    item.addEventListener('click',function(e){
        e.preventDefault();
        navigateTo(this.dataset.page);
    });
});

/* Kalkyl list/config view toggle */
function fmt(p){return p.toLocaleString('sv-SE')+' kr'}
function fmtOpt(p){return p===0?'0,00 kr':p>0?'+'+p.toLocaleString('sv-SE')+' kr':p.toLocaleString('sv-SE')+' kr'}

// Lightbox
function openLightbox(url){
    const lb = document.getElementById('imgLightbox');
    const img = document.getElementById('imgLightboxImg');
    if(lb && img){ img.src = url; lb.style.display = 'flex'; }
}
function closeLightbox(){
    const lb = document.getElementById('imgLightbox');
    if(lb) lb.style.display = 'none';
}

// Spara kalkyl från steg 1 (konfiguratorn, utan affär)
function closeModal(){const m=document.getElementById('quoteModal');if(m)m.classList.remove('active');document.body.style.overflow=''}
function submitQuote(e){if(e)e.preventDefault();alert('Tack! Vi återkommer.\n\n(DEMO)');closeModal()}
// === HELPERS ===
function escHtml(s) { const d = document.createElement('div'); d.textContent = s || ''; return d.innerHTML; }

// === ROLE SETTINGS (granular permissions) ===
window.gRoleSettings = window.gRoleSettings || {};
function _roleDefaultScope(){ return ['admin','systemadmin','saljchef','ekonomi'].indexOf(gUserRole) >= 0 ? 'all' : 'own'; }
function getRoleSetting(key){
    if(window.gRoleSettings && window.gRoleSettings[key] !== undefined) return window.gRoleSettings[key];
    if(key.endsWith('.scope')) return _roleDefaultScope();
    return '1';
}
function isWidgetVisible(widgetKey){ return getRoleSetting('dashboard.widget.'+widgetKey+'.visible') === '1'; }
function widgetScope(widgetKey){ return getRoleSetting('dashboard.widget.'+widgetKey+'.scope'); }
async function loadRoleSettings(){
    try {
        if(!gUserRole) return;
        const res = await fetch('/api/permissions.php?action=settings&role='+encodeURIComponent(gUserRole)+'&t='+Date.now());
        window.gRoleSettings = await res.json() || {};
        applyRoleSettings();
    } catch(e){ console.error('loadRoleSettings error', e); }
}
function applyRoleSettings(){
    const b = document.body;
    b.dataset.kalkylerPrices = getRoleSetting('kalkyler.show_prices') === '1' ? '1' : '0';
    b.dataset.produkterPrices = getRoleSetting('produkter.show_prices') === '1' ? '1' : '0';
    if(typeof loadDashboard === 'function' && document.getElementById('page-oversikt')?.classList.contains('active')) loadDashboard();
    if(typeof loadQuotesList === 'function' && document.getElementById('page-konfigurator')?.classList.contains('active')) loadQuotesList();
    if(typeof loadCustomersList === 'function' && document.getElementById('page-kunder')?.classList.contains('active')) loadCustomersList();
}
function formatMailDate(ts) {
    if (!ts) return '';
    const d = new Date(ts * 1000);
    const now = new Date();
    if (d.toDateString() === now.toDateString()) return d.toLocaleTimeString('sv-SE', {hour:'2-digit', minute:'2-digit'});
    if (d.getFullYear() === now.getFullYear()) return d.toLocaleDateString('sv-SE', {day:'numeric', month:'short'});
    return d.toLocaleDateString('sv-SE');
}
function formatSize(bytes) {
    if (bytes < 1024) return bytes + ' B';
    if (bytes < 1048576) return (bytes/1024).toFixed(0) + ' KB';
    return (bytes/1048576).toFixed(1) + ' MB';
}

// Auto-load on page navigation
// Mail/calendar hooks injected into existing navigateTo override below

// Init on load (deferred to ensure all scripts are loaded)
window.addEventListener('DOMContentLoaded', function() {
    // Auto-login from session
    if(gStaffId && gUserEmail) {
        enterApp(gUserEmail, sessionStorage.getItem('gUserAvatar') || '');
    }
    if(typeof updateAuthUI === 'function') updateAuthUI();
    if(typeof loadCurrencySettings === 'function') loadCurrencySettings();
    if(typeof loadCatalogFromDB === 'function') loadCatalogFromDB();
    if(typeof initDashCharts === "function") initDashCharts();
    if(typeof loadCfgCategories === "function") loadCfgCategories();
    if(typeof loadCalcSchemasFromAPI === "function") loadCalcSchemasFromAPI();
    if(typeof applyProfileMenuPreferences === "function") applyProfileMenuPreferences();
    syncSidebarCollapse();
});

window.addEventListener('resize', syncSidebarCollapse);


// === Tax settings (loaded from DB) ===
var taxSettings = {gt20: 20, gt50: 50, rot: 30, rotMax: 50000, moms: 25};
async function loadTaxSettings() {
    try {
        var r = await fetch('/api/settings.php');
        var d = await r.json();
        if(d.success && d.settings) {
            taxSettings.gt20 = parseFloat(d.settings.tax_gt20_percent) || 20;
            taxSettings.gt50 = parseFloat(d.settings.tax_gt50_percent) || 50;
            taxSettings.rot = parseFloat(d.settings.tax_rot_percent) || 30;
            taxSettings.rotMax = parseFloat(d.settings.tax_rot_max_per_person) || 50000;
            taxSettings.moms = parseFloat(d.settings.tax_moms_percent) || 25;
        }
    } catch(e){}
}

// === Skatter settings UI ===
function loadTaxSettingsUI() {
    var gt20 = document.getElementById('taxGt20');
    var gt50 = document.getElementById('taxGt50');
    var rot = document.getElementById('taxRot');
    var rotMax = document.getElementById('taxRotMax');
    var moms = document.getElementById('taxMoms');
    if(gt20) gt20.value = taxSettings.gt20;
    if(gt50) gt50.value = taxSettings.gt50;
    if(rot) rot.value = taxSettings.rot;
    if(rotMax) rotMax.value = taxSettings.rotMax;
    if(moms) moms.value = taxSettings.moms;
}

async function saveTaxSettings() {
    var data = {
        tax_gt20_percent: document.getElementById('taxGt20').value,
        tax_gt50_percent: document.getElementById('taxGt50').value,
        tax_rot_percent: document.getElementById('taxRot').value,
        tax_rot_max_per_person: document.getElementById('taxRotMax').value,
        tax_moms_percent: document.getElementById('taxMoms').value
    };
    try {
        var r = await fetch('/api/settings.php', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(data)
        });
        var d = await r.json();
        var status = document.getElementById('taxSaveStatus');
        if(d.success) {
            if(status) { status.textContent = 'Sparat!'; status.style.color = '#059669'; }
            await loadTaxSettings();
            setTimeout(function(){ if(status) status.textContent = ''; }, 2000);
        } else {
            if(status) { status.textContent = 'Fel: ' + (d.error||''); status.style.color = '#ef4444'; }
        }
    } catch(e) {
        var status = document.getElementById('taxSaveStatus');
        if(status) { status.textContent = 'Nätverksfel'; status.style.color = '#ef4444'; }
    }
}