Cross-Sell Performance Dashboard

Cross-Sell Performance Dashboard

Analyzing Product Association and Revenue Uplift

Cross-Sell Revenue

$0

Cross-Sell Ratio

0%

Avg. Cross-Sell Value

$0

Cross-Sell Revenue by Primary Product

Top Cross-Sold Products

Transaction ID: ${t.id}

`; elements.csConfigContainer.appendChild(transactionEl); }); } // --- EVENT HANDLERS --- // function handleConfigChange(e) { if (!e.target.classList.contains('transaction-input')) return; const target = e.target; const id = parseInt(target.dataset.id); const field = target.dataset.field; const value = target.type === 'number' ? parseFloat(target.value) || 0 : target.value; const transaction = crossSellData.transactions.find(t => t.id === id); if (transaction) { transaction[field] = value; updateDashboardUI(); } } function handleAddTransaction() { const newId = crossSellData.transactions.length > 0 ? Math.max(...crossSellData.transactions.map(t => t.id)) + 1 : 1; crossSellData.transactions.unshift({ id: newId, primaryProduct: 'New Product', primaryRevenue: 0, crossSellProduct: '', crossSellRevenue: 0 }); populateConfigForm(); updateDashboardUI(); } function handleRemoveTransaction(e) { if (!e.target.classList.contains('remove-transaction-btn')) return; const id = parseInt(e.target.dataset.id); crossSellData.transactions = crossSellData.transactions.filter(t => t.id !== id); populateConfigForm(); updateDashboardUI(); } async function handlePdfDownload() { if (typeof html2canvas === 'undefined' || typeof window.jspdf === 'undefined') return; const { jsPDF } = window.jspdf; const pdfExportElement = elements.pdfExportArea; if (!pdfExportElement) return; const originalBg = pdfExportElement.style.backgroundColor; pdfExportElement.style.backgroundColor = 'white'; try { const canvas = await html2canvas(pdfExportElement, { scale: 2, useCORS: true, logging: false }); pdfExportElement.style.backgroundColor = originalBg; 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('Cross-Sell-Performance-Dashboard.pdf'); } catch (error) { console.error("Error generating PDF:", error); pdfExportElement.style.backgroundColor = originalBg; } } // --- INITIALIZATION --- // if (elements.csConfigContainer) { elements.csConfigContainer.addEventListener('input', handleConfigChange); elements.csConfigContainer.addEventListener('click', handleRemoveTransaction); } if (elements.addTransactionBtn) { elements.addTransactionBtn.addEventListener('click', handleAddTransaction); } if (elements.downloadPdfBtn) { elements.downloadPdfBtn.addEventListener('click', handlePdfDownload); } updateDashboardUI(); populateConfigForm(); window.updateNavButtons(); }); // --- GLOBAL FUNCTIONS FOR TAB NAVIGATION --- // function switchTab(tabName) { const tabDashboard = document.getElementById('tab-panel-dashboard'); const tabConfig = document.getElementById('tab-panel-config'); const btnDashboard = document.getElementById('tab-btn-dashboard'); const btnConfig = document.getElementById('tab-btn-config'); if (!tabDashboard || !tabConfig || !btnDashboard || !btnConfig) return; const isDashboard = tabName === 'dashboard'; tabDashboard.classList.toggle('hidden', !isDashboard); tabConfig.classList.toggle('hidden', isDashboard); btnDashboard.classList.toggle('active', isDashboard); btnConfig.classList.toggle('active', !isDashboard); updateNavButtons(); } function updateNavButtons() { const btnDashboard = document.getElementById('tab-btn-dashboard'); const prevBtn = document.getElementById('prev-btn'); const nextBtn = document.getElementById('next-btn'); if (!btnDashboard || !prevBtn || !nextBtn) return; const isDashboardActive = btnDashboard.classList.contains('active'); prevBtn.disabled = isDashboardActive; nextBtn.disabled = !isDashboardActive; prevBtn.classList.toggle('opacity-50', isDashboardActive); prevBtn.classList.toggle('cursor-not-allowed', isDashboardActive); nextBtn.classList.toggle('opacity-50', !isDashboardActive); nextBtn.classList.toggle('cursor-not-allowed', !isDashboardActive); } function navigateTabs(direction) { const isDashboardActive = document.getElementById('tab-btn-dashboard').classList.contains('active'); if (direction === 'next' && isDashboardActive) { switchTab('config'); } else if (direction === 'prev' && !isDashboardActive) { switchTab('dashboard'); } }
Scroll to Top