Gender Diversity
${diversityRatio}
Avg. Performance
${avgPerformance.toFixed(1)} / 5
Turnover Rate (YTD)
${turnoverRate.toFixed(1)}%
`;
};
const renderDataTable = () => {
dataTableBody.innerHTML = '';
const sortedEmployees = [...state.employees].sort((a, b) => new Date(b.hireDate) - new Date(a.hireDate));
sortedEmployees.forEach(e => {
const status = e.termDate ? 'Inactive' : 'Active';
const row = `
| ${e.id} |
${e.department} |
${e.performance} |
${e.hireDate} |
${status} |
`;
dataTableBody.innerHTML += row;
});
};
const renderCharts = () => {
const activeEmployees = state.employees.filter(e => !e.termDate);
// Headcount by Department
const headcountByDept = activeEmployees.reduce((acc, e) => {
acc[e.department] = (acc[e.department] || 0) + 1;
return acc;
}, {});
const deptLabels = Object.keys(headcountByDept);
const deptData = deptLabels.map(label => headcountByDept[label]);
if (departmentChart) departmentChart.destroy();
departmentChart = new Chart(departmentCanvas.getContext('2d'), {
type: 'bar',
data: {
labels: deptLabels,
datasets: [{ label: 'Headcount', data: deptData, backgroundColor: 'rgba(14, 165, 233, 0.7)' }]
},
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } } }
});
// Performance Distribution
const perfDist = activeEmployees.reduce((acc, e) => {
if (e.performance <= 2) acc['Low']++;
else if (e.performance <= 4) acc['Medium']++;
else acc['High']++;
return acc;
}, { 'Low': 0, 'Medium': 0, 'High': 0 });
if (performanceChart) performanceChart.destroy();
performanceChart = new Chart(performanceCanvas.getContext('2d'), {
type: 'doughnut',
data: {
labels: ['Low (1-2)', 'Medium (3-4)', 'High (5)'],
datasets: [{ data: [perfDist['Low'], perfDist['Medium'], perfDist['High']], backgroundColor: ['#f87171', '#facc15', '#4ade80'] }]
},
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top' } } }
});
};
const renderConfigRows = () => {
configRowsContainer.innerHTML = '';
const sortedEmployees = [...state.employees].sort((a,b) => b.id.localeCompare(a.id));
sortedEmployees.forEach(e => {
configRowsContainer.innerHTML += `
`.replaceAll('class="config-input"', 'class="config-input w-full border-gray-300 rounded-md shadow-sm"');
});
addConfigEventListeners();
};
// --- EVENT HANDLERS ---
const handleConfigChange = (e) => {
const id = e.target.dataset.id;
const field = e.target.dataset.field;
const value = e.target.value;
const employee = state.employees.find(emp => emp.id === id);
if (employee) {
if (field === 'performance') employee[field] = parseInt(value, 10);
else if (field === 'termDate' && value === '') employee[field] = null;
else employee[field] = value;
}
renderAll();
};
const handleAddEmployee = () => {
const newId = 'E' + (Math.max(...state.employees.map(e => parseInt(e.id.substring(1)))) + 1);
const today = new Date().toISOString().split('T')[0];
state.employees.push({ id: newId, department: "Unassigned", gender: "Male", performance: 3, hireDate: today, termDate: null });
renderAll();
};
const handleRemoveEmployee = (e) => {
const id = e.target.dataset.id;
state.employees = state.employees.filter(emp => emp.id !== id);
renderAll();
};
const addConfigEventListeners = () => {
document.querySelectorAll('.config-input').forEach(input => input.addEventListener('change', handleConfigChange));
document.querySelectorAll('.remove-btn').forEach(button => button.addEventListener('click', handleRemoveEmployee));
};
const handleDownloadPdf = () => {
const { jsPDF } = window.jspdf;
const pdfContent = document.getElementById('pdf-content');
document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'hidden');
Chart.defaults.animation = false;
html2canvas(pdfContent, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(canvas => {
document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'visible');
Chart.defaults.animation = true;
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const imgWidth = pdfWidth - 20;
const imgHeight = canvas.height * imgWidth / canvas.width;
pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight);
pdf.save('People-Analytics-Dashboard.pdf');
});
};
// --- TABBING LOGIC ---
let currentTabIndex = 0;
const updateTabButtons = () => {
prevTabBtn.disabled = currentTabIndex === 0;
nextTabBtn.disabled = currentTabIndex === tabContents.length - 1;
};
const switchTab = (index) => {
tabButtons.forEach(btn => btn.classList.remove('active'));
tabContents.forEach(content => content.classList.remove('active'));
tabButtons[index].classList.add('active');
tabContents[index].classList.add('active');
currentTabIndex = index;
updateTabButtons();
};
tabButtons.forEach((button, index) => button.addEventListener('click', () => switchTab(index)));
prevTabBtn.addEventListener('click', () => { if (currentTabIndex > 0) switchTab(currentTabIndex - 1); });
nextTabBtn.addEventListener('click', () => { if (currentTabIndex < tabContents.length - 1) switchTab(currentTabIndex + 1); });
// --- INITIALIZATION ---
if (kpiContainer && addEmployeeBtn && downloadPdfBtn) {
addEmployeeBtn.addEventListener('click', handleAddEmployee);
downloadPdfBtn.addEventListener('click', handleDownloadPdf);
renderAll();
updateTabButtons();
} else {
console.error("Essential dashboard elements could not be found.");
}
});