document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById('active-projects-container') const tabLink = document.querySelector('a[href="#active-projects"]') const tabPane = document.getElementById('active-projects') if (!container || !tabPane) return let isLoaded = false let isLoading = false function loadActiveProjects() { if (isLoaded || isLoading) return isLoading = true // show loading only if tab is visible if (tabPane.classList.contains('active')) { container.innerHTML = '

Loading...

' } fetch('/admin/active-projects') .then(res => res.json()) .then(data => { container.innerHTML = renderTable(data) isLoaded = true }) .catch(() => { container.innerHTML = '

Failed to load active projects

' }) .finally(() => { isLoading = false }) } // preload immediately when /admin page opens loadActiveProjects() // ensure data is loaded when tab is opened if (tabLink) { tabLink.addEventListener('shown.bs.tab', () => { if (!isLoaded) loadActiveProjects() }) } }) function renderTable(data) { if (!Array.isArray(data) || data.length === 0) { return `
✔ Great news! No projects are currently being edited.
` } const rows = data.map((project, projectIndex) => { const users = project.activeUsers || [] const mailto = users .map(u => u.email) .filter(Boolean) .join(',') const projectName = mailto ? `${project.name}` : project.name const stripedStyle = projectIndex % 2 === 1 ? 'background-color: var(--bs-table-striped-bg);' : '' const usersHtml = users.length ? users.map(user => `
${ user.email ? `${user.name}` : user.name }
`).join('') : 'None detected' return `
${projectName}
${usersHtml}
` }).join('') return `

${data.length} project(s) currently being edited

Project Name
Active User
${rows} ` }