Customer Journey Analysis Dashboard

Customer Journey Analysis Dashboard

Overall Journey Summary

Total Journey Records

0

Overall Conversion Rate

0%

Avg. Time to Convert (Days)

0

Total Revenue Impact ($)

$0

Conversion Rate by Stage

Average Time in Stage (Days)

Journey Status Distribution

Detailed Customer Journey Records

ID Customer Name Journey Name Current Stage Start Date Last Activity Conversion Status Conversion Date Revenue Impact ($)

No data to display.

'; return; } // Sort data by value descending for general charts, custom for specific types let sortedData = Object.entries(data); if (valueType === 'percentage') { // For conversion rate by stage, sort by stage order const stageOrder = ["Awareness", "Consideration", "Decision", "Purchase", "Retention", "Advocacy"]; sortedData.sort(([labelA], [labelB]) => stageOrder.indexOf(labelA) - stageOrder.indexOf(labelB)); } else if (valueType === 'days') { // For average time in stage, sort by stage order const stageOrder = ["Awareness", "Consideration", "Decision", "Purchase", "Retention", "Advocacy"]; sortedData.sort(([labelA], [labelB]) => stageOrder.indexOf(labelA) - stageOrder.indexOf(labelB)); } else if (valueType === 'status') { const statusOrder = ["Converted", "In Progress", "Abandoned"]; sortedData.sort(([labelA], [labelB]) => statusOrder.indexOf(labelA) - statusOrder.indexOf(labelB)); } else { sortedData.sort(([, valA], [, valB]) => valB - valA); } // Determine the maximum value for scaling bars const maxValue = Math.max(...Object.values(data), 1); // Avoid division by zero if all values are 0 sortedData.forEach(([label, value]) => { const barWidth = (value / maxValue) * 100; // Scale based on max value for visual representation const percentageOfTotal = totalValue > 0 ? ((value / totalValue) * 100).toFixed(1) : 0; let displayValue; let barClass = 'bg-blue-300'; // Default bar color if (valueType === 'percentage') { displayValue = `${value.toFixed(1)}%`; } else if (valueType === 'days') { displayValue = `${value.toFixed(0)} Days`; } else if (valueType === 'status') { displayValue = `${value} Records`; if (label === 'Converted') barClass = 'status-converted'; else if (label === 'In Progress') barClass = 'status-in-progress'; else if (label === 'Abandoned') barClass = 'status-abandoned'; } else { // 'count' displayValue = `${value} Records`; } const barWrapper = document.createElement('div'); barWrapper.classList.add('chart-bar-wrapper'); barWrapper.innerHTML = ` ${label}:
${displayValue} (${percentageOfTotal}%)
`; targetElement.appendChild(barWrapper); }); } /** * Calculates and renders all distribution charts. */ function renderDistributionCharts() { const totalJourneys = customerJourneyRecords.length; // Conversion Rate by Stage const stageConversionCounts = {}; const stageTotalCounts = {}; const stageOrder = ["Awareness", "Consideration", "Decision", "Purchase", "Retention", "Advocacy"]; stageOrder.forEach(stage => { stageConversionCounts[stage] = 0; stageTotalCounts[stage] = 0; }); customerJourneyRecords.forEach(record => { stageTotalCounts[record.currentStage] = (stageTotalCounts[record.currentStage] || 0) + 1; if (record.conversionStatus === 'Converted') { stageConversionCounts[record.currentStage] = (stageConversionCounts[record.currentStage] || 0) + 1; } }); const conversionRatesByStage = {}; stageOrder.forEach(stage => { if (stageTotalCounts[stage] > 0) { conversionRatesByStage[stage] = (stageConversionCounts[stage] / stageTotalCounts[stage]) * 100; } else { conversionRatesByStage[stage] = 0; } }); renderBarChart(conversionRateByStageChartElem, conversionRatesByStage, 'percentage'); // Average Time in Stage (Days) const timeInStageSums = {}; const timeInStageCounts = {}; stageOrder.forEach(stage => { timeInStageSums[stage] = 0; timeInStageCounts[stage] = 0; }); customerJourneyRecords.forEach(record => { const daysInStage = calculateDaysBetween(record.startDate, record.lastActivityDate); timeInStageSums[record.currentStage] = (timeInStageSums[record.currentStage] || 0) + daysInStage; timeInStageCounts[record.currentStage] = (timeInStageCounts[record.currentStage] || 0) + 1; }); const avgTimeInStage = {}; stageOrder.forEach(stage => { if (timeInStageCounts[stage] > 0) { avgTimeInStage[stage] = timeInStageSums[stage] / timeInStageCounts[stage]; } else { avgTimeInStage[stage] = 0; } }); renderBarChart(avgTimeInStageChartElem, avgTimeInStage, 'days'); // Journey Status Distribution const journeyStatusCounts = customerJourneyRecords.reduce((acc, record) => { acc[record.conversionStatus] = (acc[record.conversionStatus] || 0) + 1; return acc; }, {}); renderBarChart(journeyStatusDistributionChartElem, journeyStatusCounts, 'status'); } /** * Generates a PDF of the dashboard content. * Excludes non-essential UI elements like buttons and input forms. */ function generatePdf() { // Create a temporary div to hold only the content for PDF const pdfContentWrapper = document.createElement('div'); pdfContentWrapper.classList.add('pdf-content-wrapper'); // Apply PDF-specific styles // Add title const title = document.createElement('h2'); title.textContent = 'Customer Journey Analysis Report'; title.classList.add('text-2xl', 'font-bold', 'mb-4'); pdfContentWrapper.appendChild(title); // Add summary cards const summarySection = document.createElement('div'); summarySection.classList.add('grid', 'grid-cols-4', 'gap-4', 'mb-6'); summarySection.innerHTML = `

Total Journey Records

${totalJourneysCountElem.textContent}

Overall Conversion Rate

${overallConversionRateElem.textContent}

Avg. Time to Convert (Days)

${avgTimeToConvertElem.textContent}

Total Revenue Impact ($)

${totalRevenueImpactElem.textContent}

`; pdfContentWrapper.appendChild(summarySection); // Add distribution charts const chartsSection = document.createElement('div'); chartsSection.classList.add('grid', 'grid-cols-2', 'gap-6', 'mb-6'); chartsSection.innerHTML = `

Conversion Rate by Stage

Average Time in Stage (Days)

Journey Status Distribution

`; pdfContentWrapper.appendChild(chartsSection); // Populate PDF charts (re-use logic but target PDF elements) const totalJourneys = customerJourneyRecords.length; const stageOrder = ["Awareness", "Consideration", "Decision", "Purchase", "Retention", "Advocacy"]; // Conversion Rate by Stage for PDF const stageConversionCountsPdf = {}; const stageTotalCountsPdf = {}; stageOrder.forEach(stage => { stageConversionCountsPdf[stage] = 0; stageTotalCountsPdf[stage] = 0; }); customerJourneyRecords.forEach(record => { stageTotalCountsPdf[record.currentStage] = (stageTotalCountsPdf[record.currentStage] || 0) + 1; if (record.conversionStatus === 'Converted') { stageConversionCountsPdf[record.currentStage] = (stageConversionCountsPdf[record.currentStage] || 0) + 1; } }); const conversionRatesByStagePdf = {}; stageOrder.forEach(stage => { if (stageTotalCountsPdf[stage] > 0) { conversionRatesByStagePdf[stage] = (stageConversionCountsPdf[stage] / stageTotalCountsPdf[stage]) * 100; } else { conversionRatesByStagePdf[stage] = 0; } }); renderBarChart(chartsSection.querySelector('#pdfConversionRateByStageChart'), conversionRatesByStagePdf, 'percentage'); // Average Time in Stage (Days) for PDF const timeInStageSumsPdf = {}; const timeInStageCountsPdf = {}; stageOrder.forEach(stage => { timeInStageSumsPdf[stage] = 0; timeInStageCountsPdf[stage] = 0; }); customerJourneyRecords.forEach(record => { const daysInStage = calculateDaysBetween(record.startDate, record.lastActivityDate); timeInStageSumsPdf[record.currentStage] = (timeInStageSumsPdf[record.currentStage] || 0) + daysInStage; timeInStageCountsPdf[record.currentStage] = (timeInStageCountsPdf[record.currentStage] || 0) + 1; }); const avgTimeInStagePdf = {}; stageOrder.forEach(stage => { if (timeInStageCountsPdf[stage] > 0) { avgTimeInStagePdf[stage] = timeInStageSumsPdf[stage] / timeInStageCountsPdf[stage]; } else { avgTimeInStagePdf[stage] = 0; } }); renderBarChart(chartsSection.querySelector('#pdfAvgTimeInStageChart'), avgTimeInStagePdf, 'days'); // Journey Status Distribution for PDF const journeyStatusCountsPdf = customerJourneyRecords.reduce((acc, record) => { acc[record.conversionStatus] = (acc[record.conversionStatus] || 0) + 1; return acc; }, {}); renderBarChart(chartsSection.querySelector('#pdfJourneyStatusDistributionChart'), journeyStatusCountsPdf, 'status'); // Add detailed journey list table const journeyListSection = document.createElement('div'); journeyListSection.innerHTML = `

Detailed Customer Journey Records

${dashboardJourneyTableBody.innerHTML}
ID Customer Name Journey Name Current Stage Start Date Last Activity Conversion Status Conversion Date Revenue Impact ($)
`; pdfContentWrapper.appendChild(journeyListSection); // Options for html2pdf const options = { margin: 10, filename: 'Customer_Journey_Dashboard.pdf', image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2, logging: true, dpi: 192, letterRendering: true }, jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }, pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } }; // Generate PDF from the temporary content wrapper html2pdf().from(pdfContentWrapper).set(options).save(); // Clean up the temporary div (optional, as it's not appended to the DOM) pdfContentWrapper.remove(); } /** * Loads initial sample data for the dashboard. * Relevant to USA context. */ function loadSampleData() { customerJourneyRecords = [ { id: 'CJ001', customerName: 'Alice Smith', journeyName: 'Onboarding Flow', currentStage: 'Purchase', startDate: '2024-01-01', lastActivityDate: '2024-01-15', conversionStatus: 'Converted', conversionDate: '2024-01-15', revenueImpact: 250.00 }, { id: 'CJ002', customerName: 'Bob Johnson', journeyName: 'Product Discovery', currentStage: 'Consideration', startDate: '2024-01-10', lastActivityDate: '2024-02-01', conversionStatus: 'In Progress', conversionDate: '', revenueImpact: 0 }, { id: 'CJ003', customerName: 'Charlie Brown', journeyName: 'Subscription Renewal', currentStage: 'Retention', startDate: '2023-12-01', lastActivityDate: '2024-01-20', conversionStatus: 'Abandoned', conversionDate: '', revenueImpact: 0 }, { id: 'CJ004', customerName: 'Diana Prince', journeyName: 'Onboarding Flow', currentStage: 'Advocacy', startDate: '2024-02-01', lastActivityDate: '2024-02-28', conversionStatus: 'Converted', conversionDate: '2024-02-20', revenueImpact: 100.00 }, { id: 'CJ005', customerName: 'Ethan Hunt', journeyName: 'Product Discovery', currentStage: 'Awareness', startDate: '2024-03-01', lastActivityDate: '2024-03-05', conversionStatus: 'In Progress', conversionDate: '', revenueImpact: 0 }, { id: 'CJ006', customerName: 'Fiona Green', journeyName: 'Purchase Funnel', currentStage: 'Decision', startDate: '2024-03-10', lastActivityDate: '2024-03-25', conversionStatus: 'Converted', conversionDate: '2024-03-25', revenueImpact: 500.00 } ]; }
Scroll to Top