const API_BASE = window.location.hostname === 'localhost' ? 'http://localhost:9092' : 'https://landvex.com'; let token = localStorage.getItem('boc_token'); // Navigation document.querySelectorAll('.sidebar-nav a').forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); const module = link.dataset.module; showModule(module); document.querySelectorAll('.sidebar-nav a').forEach(l => l.classList.remove('active')); link.classList.add('active'); }); }); function showModule(name) { document.querySelectorAll('.module').forEach(m => m.classList.remove('active')); document.getElementById(name).classList.add('active'); // Load module data switch(name) { case 'dashboard': loadDashboard(); break; case 'crm': loadCRM(); break; case 'sales': loadSales(); break; case 'finance': loadFinance(); break; case 'support': loadSupport(); break; case 'analytics': loadAnalytics(); break; } } async function api(path, options = {}) { const res = await fetch(`${API_BASE}${path}`, { ...options, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, ...options.headers, }, }); if (res.status === 401) { localStorage.removeItem('boc_token'); window.location.href = '/login.html'; return; } return res.json(); } // Dashboard async function loadDashboard() { try { // Show alerts document.getElementById('alerts-container').style.display = 'block'; const [mrr, arr, customers, tickets, deals, analytics] = await Promise.all([ api('/api/v1/sales/mrr'), api('/api/v1/sales/arr'), api('/api/v1/crm/customers'), api('/api/v1/support/tickets'), api('/api/v1/sales/deals'), api('/api/v1/analytics/users') ]); document.getElementById('kpi-mrr').textContent = formatCurrency(mrr.mrr); document.getElementById('kpi-arr').textContent = formatCurrency(arr.arr); document.getElementById('kpi-customers').textContent = customers.total || 0; document.getElementById('kpi-tickets').textContent = (tickets.tickets || []).filter(t => t.status === 'open').length; document.getElementById('kpi-cash').textContent = '276 504'; const pipelineValue = (deals.deals || []) .filter(d => d.status === 'open') .reduce((sum, d) => sum + (d.value || 0), 0); document.getElementById('kpi-pipeline').textContent = formatCurrency(pipelineValue); // Recent deals const recentDeals = document.getElementById('recent-deals'); recentDeals.innerHTML = (deals.deals || []).slice(0, 5).map(d => `
${d.name}
${d.stage}
${formatCurrency(d.value)}
${d.status}
`).join(''); // Recent tickets const recentTickets = document.getElementById('recent-tickets'); recentTickets.innerHTML = (tickets.tickets || []).filter(t => t.status === 'open').slice(0, 5).map(t => `
${t.subject}
${t.assigned_to?.String || 'Ej tilldelad'}
${t.priority}
`).join(''); } catch (err) { console.error('Failed to load dashboard:', err); } } // CRM async function loadCRM() { try { const data = await api('/api/v1/crm/customers'); const tbody = document.querySelector('#customers-table tbody'); tbody.innerHTML = (data.customers || []).map(c => ` ${c.name} ${c.company} ${c.status} ${c.source} ${formatDate(c.created_at)} `).join(''); } catch (err) { console.error('Failed to load CRM:', err); } } // Sales async function loadSales() { try { const data = await api('/api/v1/sales/deals'); const tbody = document.querySelector('#deals-table tbody'); tbody.innerHTML = (data.deals || []).map(d => ` ${d.name} ${d.customer_id} ${formatCurrency(d.value)} ${d.status} ${d.stage} ${formatDate(d.expected_close)} `).join(''); } catch (err) { console.error('Failed to load sales:', err); } } // Finance async function loadFinance() { try { const data = await api('/api/v1/finance/invoices'); const tbody = document.querySelector('#invoices-table tbody'); tbody.innerHTML = (data.invoices || []).map(i => ` ${i.id} ${i.customer_id} ${formatCurrency(i.amount)} ${i.status} ${i.due_date?.Valid ? formatDate(i.due_date.String) : '-'} `).join(''); } catch (err) { console.error('Failed to load finance:', err); } } // Support async function loadSupport() { try { const data = await api('/api/v1/support/tickets'); const tbody = document.querySelector('#tickets-table tbody'); tbody.innerHTML = (data.tickets || []).map(t => ` ${t.subject} ${t.customer_id} ${t.priority} ${t.status} ${t.assigned_to?.String || 'Ej tilldelad'} `).join(''); } catch (err) { console.error('Failed to load support:', err); } } // Analytics async function loadAnalytics() { try { const [users, revenue, retention] = await Promise.all([ api('/api/v1/analytics/users'), api('/api/v1/analytics/revenue'), api('/api/v1/analytics/retention') ]); document.getElementById('analytics-dau').textContent = (users.daily_active || 0).toLocaleString('sv-SE'); document.getElementById('analytics-revenue').textContent = formatCurrency(revenue.revenue_this_month || 0); document.getElementById('analytics-retention').textContent = (retention.day_30 || 0) + '%'; } catch (err) { console.error('Failed to load analytics:', err); } } // Modal function showModal(type) { const modal = document.getElementById('modal'); const title = document.getElementById('modal-title'); const body = document.getElementById('modal-body'); modal.style.display = 'flex'; if (type === 'new-customer') { title.textContent = 'Ny kund'; body.innerHTML = `
`; } else if (type === 'new-deal') { title.textContent = 'Ny deal'; body.innerHTML = `
`; } } function hideModal() { document.getElementById('modal').style.display = 'none'; } async function createCustomer() { const name = document.getElementById('new-customer-name').value; const email = document.getElementById('new-customer-email').value; const phone = document.getElementById('new-customer-phone').value; const status = document.getElementById('new-customer-status').value; if (!name) { alert('Namn krävs'); return; } try { await api('/api/v1/crm/customers', { method: 'POST', body: JSON.stringify({ name, email, phone, status }) }); hideModal(); loadCRM(); } catch (err) { alert('Kunde inte skapa kund: ' + err.message); } } async function createDeal() { const name = document.getElementById('new-deal-name').value; const value = parseFloat(document.getElementById('new-deal-value').value); const stage = document.getElementById('new-deal-stage').value; if (!name || !value) { alert('Namn och värde krävs'); return; } try { await api('/api/v1/sales/deals', { method: 'POST', body: JSON.stringify({ name, value, stage, status: 'open' }) }); hideModal(); loadSales(); } catch (err) { alert('Kunde inte skapa deal: ' + err.message); } } // Helpers function formatCurrency(value) { return new Intl.NumberFormat('sv-SE').format(value || 0) + ' SEK'; } function formatDate(dateStr) { if (!dateStr) return '-'; const date = new Date(dateStr); return date.toLocaleDateString('sv-SE'); } function logout() { localStorage.removeItem('boc_token'); window.location.href = '/login.html'; } // Init document.addEventListener('DOMContentLoaded', () => { if (!token && !window.location.pathname.includes('login')) { window.location.href = '/login.html'; return; } loadDashboard(); });