// 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'; }
}
}