Customer Lifecycle Support Dashboard

Customer Lifecycle Support Dashboard

Key Support Performance Indicators

Lifecycle Support Insights

No insights generated yet. Please configure your data.

Customer Lifecycle Support Dashboard Report

Key Support Performance Indicators

Lifecycle Support Insights

Potential Bottlenecks: Metrics requiring attention (e.g., resolution time exceeding target) include: ${inverseBelow}. Investigate root causes and implement corrective actions.

`; } } if (insightsHtml === '') { insightsHtml = '

No specific insights generated. Ensure your metrics have valid target and actual values.

'; } } supportInsights.innerHTML = insightsHtml; } // --- Event Handlers (Globally accessible for onclick attributes) --- /** * Switches between dashboard and data configuration tabs. * @param {string} tabName - 'dashboard' or 'dataConfig'. */ window.switchTab = function(tabName) { // Guard clauses for elements if (!dashboardTabBtn || !dataConfigTabBtn || !dashboardTabContent || !dataConfigTabContent || !prevTabBtn || !nextTabBtn) { console.error("One or more tab elements not found."); return; } currentTab = tabName; // Update button styles dashboardTabBtn.classList.remove('active'); dataConfigTabBtn.classList.remove('active'); dashboardTabContent.classList.add('hidden'); dataConfigTabContent.classList.add('hidden'); if (tabName === 'dashboard') { dashboardTabBtn.classList.add('active'); dashboardTabContent.classList.remove('hidden'); prevTabBtn.disabled = true; nextTabBtn.disabled = false; renderAllKpiCards(); // Re-render dashboard content when tab is active generateSupportInsights(); // Re-generate insights } else if (tabName === 'dataConfig') { dataConfigTabBtn.classList.add('active'); dataConfigTabContent.classList.remove('hidden'); prevTabBtn.disabled = false; nextTabBtn.disabled = true; renderAllMetricInputRows(); // Re-render input rows when tab is active } }; /** * Navigates between tabs using 'Next' and 'Previous' buttons. * @param {string} direction - 'prev' or 'next'. */ window.navigateTabs = function(direction) { if (direction === 'next') { if (currentTab === 'dashboard') { switchTab('dataConfig'); } } else if (direction === 'prev') { if (currentTab === 'dataConfig') { switchTab('dashboard'); } } }; /** * Adds a new empty metric row to the data configuration. */ if (addMetricBtn) { // Null check for addMetricBtn addMetricBtn.onclick = function() { const newMetricId = generateUniqueId(); const newMetric = { id: newMetricId, name: '', target: null, actual: null, unit: '' }; supportMetrics.push(newMetric); renderMetricInputRow(newMetric); showMessage('New metric row added.', 'info'); }; } /** * Updates a specific property of a metric in the supportMetrics array. * This function is called directly from input fields' oninput. * @param {string} id - The ID of the metric to update. * @param {string} property - The property to update ('name', 'target', 'actual', 'unit'). * @param {*} value - The new value for the property. */ window.updateMetricValue = function(id, property, value) { const metricIndex = supportMetrics.findIndex(m => m.id === id); if (metricIndex !== -1) { supportMetrics[metricIndex][property] = value; } }; /** * Removes a metric from the supportMetrics array and its corresponding input row. * @param {string} id - The ID of the metric to remove. */ window.removeMetric = function(id) { supportMetrics = supportMetrics.filter(m => m.id !== id); const metricRow = document.getElementById(`metric-row-${id}`); if (metricRow) { metricRow.remove(); showMessage('Metric removed successfully.', 'success'); } else { console.warn(`Metric row with ID ${id} not found for removal.`); } }; /** * Saves the data (which is already updated via oninput) and refreshes the dashboard. */ if (saveDataBtn) { // Null check for saveDataBtn saveDataBtn.onclick = function() { // Filter out any metrics that are completely empty or invalid supportMetrics = supportMetrics.filter(metric => metric.name.trim() !== '' || (typeof metric.target === 'number' && !isNaN(metric.target)) || (typeof metric.actual === 'number' && !isNaN(metric.actual)) ); // Ensure all numerical values are indeed numbers supportMetrics.forEach(metric => { metric.target = parseFloat(metric.target) || 0; metric.actual = parseFloat(metric.actual) || 0; }); renderAllKpiCards(); // Re-render dashboard generateSupportInsights(); // Re-generate insights showMessage('Data saved and dashboard updated!', 'success'); }; } /** * Handles the PDF download functionality. */ if (downloadPdfBtn) { // Null check for downloadPdfBtn downloadPdfBtn.onclick = async function() { if (!pdfContent || !pdfKpiMetrics || !pdfSupportInsights) { console.error("PDF content elements not found."); showMessage('Error: PDF content elements missing.', 'error'); return; } // Populate the hidden PDF content div with current dashboard data pdfKpiMetrics.innerHTML = `

Key Support Performance Indicators

`; if (supportMetrics.length === 0) { pdfKpiMetrics.innerHTML += '

No KPI data available.

'; } else { let kpiTableHtml = ` `; supportMetrics.forEach(metric => { const progress = calculateProgress(metric.actual, metric.target, metric.name); kpiTableHtml += ` `; }); kpiTableHtml += `
Metric Name Target Value Actual Value Unit Progress (%)
${metric.name || 'N/A'} ${formatValue(metric.target, metric.unit)} ${formatValue(metric.actual, metric.unit)} ${metric.unit || 'N/A'} ${progress.toFixed(2)}%
`; pdfKpiMetrics.innerHTML += kpiTableHtml; } // Populate support insights for PDF let insightsForPdf = ''; if (supportMetrics.length === 0) { insightsForPdf = '

No insights generated. Please configure your data.

'; } else { let overallProgress = 0; let metricsBelowTarget = []; let metricsAboveTarget = []; supportMetrics.forEach(metric => { const progress = calculateProgress(metric.actual, metric.target, metric.name); overallProgress += progress; if (metric.name.toLowerCase().includes('average resolution time')) { if (metric.actual > metric.target) { metricsBelowTarget.push({ name: metric.name, progress: progress.toFixed(2), type: 'inverse' }); } else { metricsAboveTarget.push({ name: metric.name, progress: progress.toFixed(2), type: 'inverse' }); } } else { if (progress < 100 && metric.actual < metric.target) { metricsBelowTarget.push({ name: metric.name, progress: progress.toFixed(2), type: 'direct' }); } else if (progress >= 100 && metric.actual >= metric.target) { metricsAboveTarget.push({ name: metric.name, progress: progress.toFixed(2), type: 'direct' }); } } }); const avgProgress = supportMetrics.length > 0 ? (overallProgress / supportMetrics.length).toFixed(2) : 0; insightsForPdf += `

Overall Support Performance: The average progress across all defined metrics is ${avgProgress}%.

`; if (metricsAboveTarget.length > 0) { const directAbove = metricsAboveTarget.filter(m => m.type === 'direct').map(m => `${m.name} (${m.progress}%)`).join(', '); const inverseAbove = metricsAboveTarget.filter(m => m.type === 'inverse').map(m => `${m.name} (Achieved: ${formatValue(supportMetrics.find(sm => sm.name === m.name).actual, supportMetrics.find(sm => sm.name === m.name).unit)}, Target: ${formatValue(supportMetrics.find(sm => sm.name === m.name).target, supportMetrics.find(sm => sm.name === m.name).unit)})`).join(', '); if (directAbove) { insightsForPdf += `

Strengths: Excellent performance observed in: ${directAbove}. Continue to leverage these areas.

`; } if (inverseAbove) { insightsForPdf += `

Efficiency Gains: Metrics showing favorable trends (e.g., resolution time meeting target) include: ${inverseAbove}. This indicates strong operational efficiency.

`; } } if (metricsBelowTarget.length > 0) { const directBelow = metricsBelowTarget.filter(m => m.type === 'direct').map(m => `${m.name} (${m.progress}%)`).join(', '); const inverseBelow = metricsBelowTarget.filter(m => m.type === 'inverse').map(m => `${m.name} (Achieved: ${formatValue(supportMetrics.find(sm => sm.name === m.name).actual, supportMetrics.find(sm => sm.name === m.name).unit)}, Target: ${formatValue(supportMetrics.find(sm => sm.name === m.name).target, supportMetrics.find(sm => sm.name === m.name).unit)})`).join(', '); if (directBelow) { insightsForPdf += `

Areas for Improvement: Metrics currently below target include: ${directBelow}. Focus efforts on these to bridge the gap.

`; } if (inverseBelow) { insightsForPdf += `

Potential Bottlenecks: Metrics requiring attention (e.g., resolution time exceeding target) include: ${inverseBelow}. Investigate root causes and implement corrective actions.

`; } } insightsForPdf += `
`; } pdfSupportInsights.innerHTML = `

Lifecycle Support Insights

${insightsForPdf}`; // Show the hidden content temporarily for html2canvas to render it pdfContent.style.display = 'block'; showMessage('Generating PDF...', 'info'); try { const canvas = await html2canvas(pdfContent, { scale: 2, // Increase scale for better quality useCORS: true, // If you have external images, enable CORS logging: false // Disable console logging from html2canvas }); const imgData = canvas.toDataURL('image/png'); const { jsPDF } = window.jspdf; const pdf = new jsPDF('p', 'mm', 'a4'); // 'p' for portrait, 'mm' for millimeters, 'a4' size const imgWidth = 210; // A4 width in mm const pageHeight = 297; // A4 height in mm const imgHeight = canvas.height * imgWidth / canvas.width; let heightLeft = imgHeight; let position = 0; pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; while (heightLeft >= 0) { position = heightLeft - imgHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; } pdf.save('Customer_Lifecycle_Support_Dashboard.pdf'); showMessage('PDF downloaded successfully!', 'success'); } catch (error) { console.error("Error generating PDF:", error); showMessage('Error generating PDF. Please try again.', 'error'); } finally { // Hide the content again after PDF generation pdfContent.style.display = 'none'; } }; } // --- Initial Load --- switchTab('dashboard'); // Start on the dashboard tab renderAllMetricInputRows(); // Render initial data in config tab renderAllKpiCards(); // Render initial data in dashboard tab generateSupportInsights(); // Generate initial insights });
Scroll to Top