with open("static/js/bottom-bar.js", "r") as f: content = f.read() # We replace everything from getCounts downwards. # Let's find the start of getCounts start_idx = content.find("function getCounts") new_logic = """function getCounts(sections) { const mail = sections.mail || {}; const cases = sections.cases || {}; const urgent = sections.urgent || {}; const timer = sections.timer || {}; const kuma = sections.kuma || {}; const eset = sections.eset || {}; return { mail: Number(mail.unread || 0), cases: Number(cases.open || 0), urgent: Number(urgent.count || 0), timer: Number(timer.active_count || 0), kuma: Number(kuma.down || 0), eset: Number(eset.incidents || 0) }; } function detailTextFor(key, sections) { const counts = getCounts(sections); const nameMap = { mail: 'Ubesvarede mails', cases: 'Åbne sager', urgent: 'Hastesager', timer: 'Aktive timere', kuma: 'Kuma alerts', eset: 'ESET incidents' }; const val = counts[key] || 0; return nameMap[key] + ': ' + val; } function listFor(key, sections) { const mail = sections.mail || {}; const cases = sections.cases || {}; const urgent = sections.urgent || {}; const timer = sections.timer || {}; const kuma = sections.kuma || {}; const eset = sections.eset || {}; const messages = sections.messages || {}; const tasks = sections.tasks || {}; const boss = sections.boss || {}; if (key === 'overview') { return [ 'Velkommen til dit overblik', 'Her vises det vigtigste på tværs af systemet', 'Næste opgave kl. 14:00' ]; } if (key === 'timer') { if (timer.active_count > 0) { return (timer.list || []).map(t => 'Timer aktiv: ' + t.description); } return ['Ingen aktive timere lige nu.']; } if (key === 'messages') { if (messages.count > 0) { return (messages.list || []).map(m => m.from + ': ' + m.text); } return ['Ingen nye beskeder.']; } if (key === 'tasks') { if (tasks.count > 0) { return (tasks.list || []).map(t => t.title + ' (Deadline: ' + t.deadline + ')'); } return ['Ingen aktuelle opgaver.']; } if (key === 'boss') { if (boss.stats) { return [ 'Ufordelte opgaver: ' + boss.stats.unassigned, 'Medarbejdere aktive: ' + boss.stats.active_employees ]; } return ['Henter chef-overblik...']; } return ['Klik rundt i menuen for at se data for ' + key]; } function updateBar(sections) { const counts = getCounts(sections); const keys = Object.keys(counts); for (let i = 0; i < keys.length; i++) { const key = keys[i]; const chipText = document.querySelector('.bb-chip[data-bb-key="' + key + '"] .bb-chip-text'); const chip = document.querySelector('.bb-chip[data-bb-key="' + key + '"]'); if (chipText && chip) { const val = counts[key]; const labels = { mail: 'Mails', cases: 'Sager', urgent: 'Hastesager', timer: 'Timere', kuma: 'Kuma', eset: 'ESET' }; chipText.textContent = labels[key] + ': ' + val; chip.classList.toggle('has-items', val > 0); } } } function renderTabPanel() { const titleContainer = byId('bbTabTitle'); const innerContent = byId('bbTabInnerContent'); if (!titleContainer || !innerContent) { return; } const titleText = titleContainer.querySelector('.bb-tab-title-text'); const titleByKey = { overview: 'Overblik', timer: 'Timere', messages: 'Beskeder', tasks: 'Opgaver', boss: 'Chef Dashboard' }; const iconByKey = { overview: 'bi-bell', timer: 'bi-stopwatch', messages: 'bi-chat-dots', tasks: 'bi-calendar-check', boss: 'bi-person-workspace' }; const activeTitle = titleByKey[activeKey] || 'Info'; if (titleText) { titleText.textContent = activeTitle; } else { titleContainer.textContent = activeTitle; } const iconSpan = titleContainer.querySelector('.bi'); if (iconSpan) { iconSpan.className = 'bi ' + (iconByKey[activeKey] || 'bi-info-circle') + ' me-2 text-accent'; } // Render lists const lines = listFor(activeKey, latestSections); const ul = document.createElement('ul'); ul.className = 'bb-tab-list'; lines.forEach(function (line) { const li = document.createElement('li'); li.innerHTML = String(line) .replaceAll('&', '&') .replaceAll('<', '<') .replaceAll('>', '>'); ul.appendChild(li); }); innerContent.innerHTML = ''; innerContent.appendChild(ul); } function bindSideTabs() { const buttons = document.querySelectorAll('.bb-tab-btn'); for (let i = 0; i < buttons.length; i++) { buttons[i].addEventListener('click', function () { for (let j = 0; j < buttons.length; j++) { buttons[j].classList.remove('is-active'); buttons[j].setAttribute('aria-selected', 'false'); } this.classList.add('is-active'); this.setAttribute('aria-selected', 'true'); activeKey = this.getAttribute('data-bb-tab'); renderTabPanel(); const detail = byId('bbCountDetail'); if (detail) { detail.innerHTML = ' Viser: ' + (activeKey.charAt(0).toUpperCase() + activeKey.slice(1)); } }); } } function bindChipClicks() { const chips = document.querySelectorAll('.bb-chip'); for (let i = 0; i < chips.length; i++) { chips[i].addEventListener('click', function () { const key = this.getAttribute('data-bb-key'); if (!key) return; const detail = byId('bbCountDetail'); if (detail) { detail.innerHTML = ' ' + detailTextFor(key, latestSections); } // If not expanded, expand it const shell = byId('globalBottomBar'); if (shell && !shell.classList.contains('is-expanded')) { setExpanded(true); } // Map top chip keys to side tabs if applicable, else 'overview' let targetTab = 'overview'; if (key === 'timer') targetTab = 'timer'; const tabBtn = document.querySelector('.bb-tab-btn[data-bb-tab="' + targetTab + '"]'); if (tabBtn) tabBtn.click(); }); } } function bindSheetToggle() { const toggle = byId('bbSheetToggle'); if (!toggle) return; toggle.addEventListener('click', function () { const shell = byId('globalBottomBar'); if (!shell) return; const isExp = shell.classList.contains('is-expanded'); setExpanded(!isExp); }); } function tick() { fetchBottomBarState().then(function (data) { if (data && data.enabled) { latestSections = data.sections || {}; updateBar(latestSections); renderTabPanel(); setVisibility(true); } else { setVisibility(false); } }).catch(function (err) { console.warn('Bottom bar poll failed', err); }).finally(function () { window.setTimeout(tick, 15000); }); } document.addEventListener('DOMContentLoaded', function () { activeKey = 'overview'; // Default overview state bindChipClicks(); bindSheetToggle(); bindSideTabs(); tick(); }); })(); """ combined = content[:start_idx] + new_logic with open("static/js/bottom-bar.js", "w") as f: f.write(combined)