SF Express Induction Hub | Training Dashboard
NZ Operations Hub
SF Express Logo
Safety First

Induction & Compliance

Real-time status tracking for SF Express staff across all critical health, safety, and biosecurity modules.

Total Active Staff

-

Compliance Rate

-%

Refresher Needed

-

Synchronising live Thinkific data...

`; } else if (coreIds.includes(id)) { document.getElementById('core-header').style.display = 'block'; coreGrid.appendChild(card); } else { document.getElementById('elective-header').style.display = 'block'; electiveGrid.appendChild(card); } }); // Update Global Stats document.getElementById('total-staff').textContent = totalUniqueUsers.size; document.getElementById('refresher-count').textContent = expiredCount; const rate = totalRecords > 0 ? Math.round((totalCompleted / totalRecords) * 100) : 0; document.getElementById('compliance-rate').textContent = rate + '%'; if (data.last_updated) { document.getElementById('last-updated-text').textContent = new Date(data.last_updated).toLocaleString(); } lucide.createIcons(); } function formatDate(dateStr) { if (!dateStr) return 'N/A'; const d = new Date(dateStr); return d.toLocaleDateString('en-NZ', { day: 'numeric', month: 'short', year: 'numeric' }); } function filterUsers(input) { const filter = input.value.toLowerCase(); const card = input.closest('.course-card'); const rows = card.querySelectorAll('.user-row'); rows.forEach(row => { const name = row.querySelector('.user-name').textContent.toLowerCase(); row.style.display = name.includes(filter) ? 'flex' : 'none'; }); } // Modal Functions function openReportModal(streamId) { const data = window.inductionReports; if (!data || !data.streams[streamId]) return; const stream = data.streams[streamId]; const modal = document.getElementById('report-modal'); const title = document.getElementById('modal-title'); const container = document.getElementById('modal-table-container'); const downloadBtn = document.getElementById('download-csv-btn'); title.textContent = `Full Report: ${stream.name}`; // Build Table let tableHtml = ` ${stream.data.map(u => ` `).join('')}
Staff Member Status Completion Date Expiry Date
${u.name} ${u.status} ${u.issued_at === 'Not Started' ? 'N/A' : formatDate(u.issued_at)} ${u.expiry_date ? formatDate(u.expiry_date) : 'N/A'}
`; container.innerHTML = tableHtml; modal.style.display = 'flex'; // Setup Download downloadBtn.onclick = () => downloadCSV(streamId); lucide.createIcons(); } function closeModal() { document.getElementById('report-modal').style.display = 'none'; } function downloadCSV(streamId) { const data = window.inductionReports; if (!data || !data.streams[streamId]) return; const stream = data.streams[streamId]; const headers = ['Staff Member', 'Status', 'Completion Date', 'Expiry Date']; const rows = stream.data.map(u => [ u.name, u.status, u.issued_at === 'Not Started' ? 'N/A' : u.issued_at, u.expiry_date || 'N/A' ]); let csvContent = "data:text/csv;charset=utf-8," + headers.join(",") + "\n" + rows.map(e => e.join(",")).join("\n"); const encodedUri = encodeURI(csvContent); const link = document.createElement("a"); link.setAttribute("href", encodedUri); link.setAttribute("download", `SF_Express_Report_${stream.name.replace(/\s+/g, '_')}.csv`); document.body.appendChild(link); link.click(); document.body.removeChild(link); } // Close modal on outside click window.onclick = function(event) { const modal = document.getElementById('report-modal'); if (event.target == modal) { closeModal(); } } window.onload = initDashboard;