Customer Purchase Frequency Dashboard

Customer Purchase Frequency Dashboard

Overall Purchase Metrics Summary

Total Customers

0

Total Purchases

0

Avg. Purchases per Customer

0

Repeat Customer Rate

0%

Customers by Purchase Count

Revenue by Customer Type

Revenue by Product/Service

Detailed Purchase Records

ID Customer Name Order Date Product/Service Order Value ($) Customer Purchases Is Repeat Customer?

No data to display.

'; return; } // Sort data by value descending for general charts, custom for specific types let sortedData = Object.entries(data); if (valueType === 'customerType') { const typeOrder = ['Repeat Customers', 'New Customers']; // Specific order for customer types sortedData.sort(([labelA], [labelB]) => typeOrder.indexOf(labelA) - typeOrder.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 === 'currency') { displayValue = `$${value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; } else if (valueType === 'customerType') { displayValue = `${value} Customers`; if (label === 'New Customers') barClass = 'customer-new'; else if (label === 'Repeat Customers') barClass = 'customer-repeat'; } else { // 'count' displayValue = `${value} Customers`; } 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 totalCustomers = new Set(purchaseRecords.map(record => record.customerId)).size; // Customers by Purchase Count const customerPurchaseCounts = {}; purchaseRecords.forEach(record => { customerPurchaseCounts[record.customerId] = (customerPurchaseCounts[record.customerId] || 0) + 1; }); const purchaseCountDistribution = { '1 Purchase': 0, '2 Purchases': 0, '3-5 Purchases': 0, '6+ Purchases': 0 }; for (const custId in customerPurchaseCounts) { const count = customerPurchaseCounts[custId]; if (count === 1) { purchaseCountDistribution['1 Purchase']++; } else if (count === 2) { purchaseCountDistribution['2 Purchases']++; } else if (count >= 3 && count <= 5) { purchaseCountDistribution['3-5 Purchases']++; } else if (count >= 6) { purchaseCountDistribution['6+ Purchases']++; } } renderBarChart(customersByPurchaseCountChartElem, purchaseCountDistribution, 'count'); // Revenue by Customer Type (New vs. Repeat) const revenueByCustomerType = { 'New Customers': 0, 'Repeat Customers': 0 }; const customerPurchaseDetails = {}; // To store all purchases for each customer purchaseRecords.forEach(record => { if (!customerPurchaseDetails[record.customerId]) { customerPurchaseDetails[record.customerId] = { count: 0, totalRevenue: 0 }; } customerPurchaseDetails[record.customerId].count++; customerPurchaseDetails[record.customerId].totalRevenue += record.orderValue; }); for (const custId in customerPurchaseDetails) { if (customerPurchaseDetails[custId].count === 1) { revenueByCustomerType['New Customers'] += customerPurchaseDetails[custId].totalRevenue; } else { revenueByCustomerType['Repeat Customers'] += customerPurchaseDetails[custId].totalRevenue; } } renderBarChart(revenueByCustomerTypeChartElem, revenueByCustomerType, 'currency'); // Revenue by Product/Service const revenueByProduct = purchaseRecords.reduce((acc, record) => { acc[record.productService] = (acc[record.productService] || 0) + record.orderValue; return acc; }, {}); renderBarChart(revenueByProductChartElem, revenueByProduct, 'currency'); } /** * 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 Purchase Frequency Dashboard 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 Customers

${totalCustomersCountElem.textContent}

Total Purchases

${totalPurchasesCountElem.textContent}

Avg. Purchases per Customer

${avgPurchasesPerCustomerElem.textContent}

Repeat Customer Rate

${repeatCustomerRateElem.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 = `

Customers by Purchase Count

Revenue by Customer Type

Revenue by Product/Service

`; pdfContentWrapper.appendChild(chartsSection); // Populate PDF charts (re-use logic but target PDF elements) const uniqueCustomerIds = new Set(purchaseRecords.map(record => record.customerId)); const totalCustomers = uniqueCustomerIds.size; const customerPurchaseCounts = {}; purchaseRecords.forEach(record => { customerPurchaseCounts[record.customerId] = (customerPurchaseCounts[record.customerId] || 0) + 1; }); const purchaseCountDistribution = { '1 Purchase': 0, '2 Purchases': 0, '3-5 Purchases': 0, '6+ Purchases': 0 }; for (const custId in customerPurchaseCounts) { const count = customerPurchaseCounts[custId]; if (count === 1) { purchaseCountDistribution['1 Purchase']++; } else if (count === 2) { purchaseCountDistribution['2 Purchases']++; } else if (count >= 3 && count <= 5) { purchaseCountDistribution['3-5 Purchases']++; } else if (count >= 6) { purchaseCountDistribution['6+ Purchases']++; } } renderBarChart(chartsSection.querySelector('#pdfCustomersByPurchaseCountChart'), purchaseCountDistribution, 'count'); const revenueByCustomerType = { 'New Customers': 0, 'Repeat Customers': 0 }; const customerPurchaseDetails = {}; purchaseRecords.forEach(record => { if (!customerPurchaseDetails[record.customerId]) { customerPurchaseDetails[record.customerId] = { count: 0, totalRevenue: 0 }; } customerPurchaseDetails[record.customerId].count++; customerPurchaseDetails[record.customerId].totalRevenue += record.orderValue; }); for (const custId in customerPurchaseDetails) { if (customerPurchaseDetails[custId].count === 1) { revenueByCustomerType['New Customers'] += customerPurchaseDetails[custId].totalRevenue; } else { revenueByCustomerType['Repeat Customers'] += customerPurchaseDetails[custId].totalRevenue; } } renderBarChart(chartsSection.querySelector('#pdfRevenueByCustomerTypeChart'), revenueByCustomerType, 'currency'); const revenueByProduct = purchaseRecords.reduce((acc, record) => { acc[record.productService] = (acc[record.productService] || 0) + record.orderValue; return acc; }, {}); renderBarChart(chartsSection.querySelector('#pdfRevenueByProductChart'), revenueByProduct, 'currency'); // Add detailed purchase list table const purchaseListSection = document.createElement('div'); purchaseListSection.innerHTML = `

Detailed Purchase Records

${dashboardPurchaseTableBody.innerHTML}
ID Customer Name Order Date Product/Service Order Value ($) Customer Purchases Is Repeat Customer?
`; pdfContentWrapper.appendChild(purchaseListSection); // Options for html2pdf const options = { margin: 10, filename: 'Customer_Purchase_Frequency_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() { purchaseRecords = [ { id: 'PURCH001', customerId: 'CUST001', customerName: 'Alice Johnson', orderDate: '2024-01-10', productService: 'Product A', orderValue: 120.50 }, { id: 'PURCH002', customerId: 'CUST002', customerName: 'Bob Williams', orderDate: '2024-01-15', productService: 'Service X', orderValue: 250.00 }, { id: 'PURCH003', customerId: 'CUST001', customerName: 'Alice Johnson', orderDate: '2024-02-01', productService: 'Product B', orderValue: 80.00 }, { id: 'PURCH004', customerId: 'CUST003', customerName: 'Charlie Brown', orderDate: '2024-02-10', productService: 'Product C', orderValue: 50.75 }, { id: 'PURCH005', customerId: 'CUST002', customerName: 'Bob Williams', orderDate: '2024-02-20', productService: 'Service Y', orderValue: 150.00 }, { id: 'PURCH006', customerId: 'CUST001', customerName: 'Alice Johnson', orderDate: '2024-03-05', productService: 'Product D', orderValue: 200.00 }, { id: 'PURCH007', customerId: 'CUST004', customerName: 'Diana Miller', orderDate: '2024-03-10', productService: 'Product A', orderValue: 120.50 }, { id: 'PURCH008', customerId: 'CUST001', customerName: 'Alice Johnson', orderDate: '2024-04-01', productService: 'Product E', orderValue: 30.00 }, { id: 'PURCH009', customerId: 'CUST005', customerName: 'Ethan Davis', orderDate: '2024-04-05', productService: 'Service X', orderValue: 250.00 }, { id: 'PURCH010', customerId: 'CUST002', customerName: 'Bob Williams', orderDate: '2024-04-15', productService: 'Product B', orderValue: 80.00 } ]; }
Scroll to Top