Consultant Utilization Dashboard

Consultant Utilization Dashboard

Overall Utilization

0%

Total Billable Hours

0

Total Non-Billable

0

Total Consultants

0

Utilization per Consultant

Top Performers

Detailed Utilization Report

Consultant Role Target Hours Billable Hours Utilization

${consultant.role}

${consultant.utilization.toFixed(1)}%

${consultant.billable}h Billable

`; listEl.innerHTML += item; }); }; const renderUtilizationTable = (data) => { const tableBody = document.getElementById('utilization-table-body'); tableBody.innerHTML = ''; if(data.length === 0) { tableBody.innerHTML = `No consultant data to display.`; return; } data.forEach(c => { const row = `
${c.name}
${c.role} ${c.targetHours} ${c.billable}
${c.utilization.toFixed(1)}%
`; tableBody.innerHTML += row; }); }; const renderConsultantsList = () => { const listBody = document.getElementById('consultants-list-body'); listBody.innerHTML = ''; if(consultants.length === 0) { listBody.innerHTML = `No consultants added yet.`; return; } consultants.forEach(c => { const row = ` ${c.name} ${c.role} $${c.rate} ${c.targetHours} `; listBody.innerHTML += row; }); }; const populateConsultantSelect = () => { const select = document.getElementById('hours-consultant-select'); select.innerHTML = ''; consultants.forEach(c => { const log = hoursLog.find(h => h.consultantId === c.id); // Disable option if hours are already logged to prevent duplicates in this simple model const disabled = log ? 'disabled' : ''; const suffix = log ? ' (Hours Logged)' : ''; select.innerHTML += ``; }); }; // --- EVENT HANDLERS & LOGIC --- // Tab switching tabButtons.forEach(button => { button.addEventListener('click', () => { tabButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); const tabId = button.dataset.tab; tabContents.forEach(content => { if (content.id === `${tabId}-tab`) { content.classList.remove('hidden'); } else { content.classList.add('hidden'); } }); }); }); // Consultant Form consultantForm.addEventListener('submit', (e) => { e.preventDefault(); const id = parseInt(consultantForm.querySelector('#consultant-id').value); const name = consultantForm.querySelector('#consultant-name').value; const role = consultantForm.querySelector('#consultant-role').value; const rate = parseFloat(consultantForm.querySelector('#consultant-rate').value); const targetHours = parseInt(consultantForm.querySelector('#consultant-target-hours').value); if (id) { // Update existing const index = consultants.findIndex(c => c.id === id); if (index > -1) { consultants[index] = { id, name, role, rate, targetHours }; } } else { // Add new const newId = consultants.length > 0 ? Math.max(...consultants.map(c => c.id)) + 1 : 1; consultants.push({ id: newId, name, role, rate, targetHours }); } consultantForm.reset(); consultantForm.querySelector('#consultant-id').value = ''; renderAll(); }); document.getElementById('clear-consultant-form').addEventListener('click', () => { consultantForm.reset(); consultantForm.querySelector('#consultant-id').value = ''; }); // Hours Form hoursForm.addEventListener('submit', (e) => { e.preventDefault(); const consultantId = parseInt(hoursForm.querySelector('#hours-consultant-select').value); const billable = parseInt(hoursForm.querySelector('#hours-billable').value); const nonBillable = parseInt(hoursForm.querySelector('#hours-non-billable').value); if (!consultantId) { alert('Please select a consultant.'); return; } // In this simple model, we add a new log. A more complex app would update or aggregate. const existingLog = hoursLog.find(h => h.consultantId === consultantId); if (existingLog) { alert('Hours for this consultant are already logged. Please edit their data on the dashboard or implement an "update" feature.'); return; } const newLogId = hoursLog.length > 0 ? Math.max(...hoursLog.map(h => h.logId)) + 1 : 1; hoursLog.push({ logId: newLogId, consultantId, billable, nonBillable }); hoursForm.reset(); renderAll(); }); document.getElementById('clear-hours-form').addEventListener('click', () => { hoursForm.reset(); }); // PDF Download document.getElementById('download-pdf-btn').addEventListener('click', () => { const { jsPDF } = window.jspdf; const dashboardContent = document.getElementById('dashboard-content-to-print'); const pdfButton = document.getElementById('download-pdf-btn'); // Hide button before capture pdfButton.classList.add('hidden'); html2canvas(dashboardContent, { scale: 2 // Increase scale for better resolution }).then(canvas => { // Show button again after capture pdfButton.classList.remove('hidden'); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'landscape', unit: 'px', format: [canvas.width, canvas.height] }); pdf.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height); pdf.save('Consultant_Utilization_Dashboard.pdf'); }).catch(err => { console.error("PDF generation failed:", err); // Ensure button is shown even if there's an error pdfButton.classList.remove('hidden'); }); }); // --- GLOBAL FUNCTIONS FOR ONCLICK --- window.editConsultant = (id) => { const consultant = consultants.find(c => c.id === id); if (consultant) { document.getElementById('consultant-id').value = consultant.id; document.getElementById('consultant-name').value = consultant.name; document.getElementById('consultant-role').value = consultant.role; document.getElementById('consultant-rate').value = consultant.rate; document.getElementById('consultant-target-hours').value = consultant.targetHours; // Switch to config tab for user convenience document.querySelector('.tab-btn[data-tab="config"]').click(); } }; window.deleteConsultant = (id) => { if (confirm('Are you sure you want to delete this consultant and their logged hours?')) { consultants = consultants.filter(c => c.id !== id); hoursLog = hoursLog.filter(h => h.consultantId !== id); renderAll(); } }; // --- INITIAL RENDER --- renderAll(); });
Scroll to Top