Cart Abandonment Payment Recovery Bot

Cart Abandonment Payment Recovery Bot

Simulate and analyze strategies to recover lost sales.

${formatPercent(metrics.recoveryRate)}

Abandoned Carts

${metrics.totalCarts}

Emails Sent

${metrics.emailsSent}

`; renderCharts(); document.getElementById('download-pdf-btn').addEventListener('click', generatePdf); lucide.createIcons(); }; const renderCharts = () => { // Recovery by step chart const recoveryCtx = document.getElementById('recoveryChart').getContext('2d'); const recoveryLabels = appData.strategy.map((s, i) => `Email ${i+1}`); const recoveryData = recoveryLabels.map((_, index) => cartData.filter(c => c.status === 'Recovered' && c.recoveredByStep === index + 1).reduce((sum, c) => sum + c.value, 0) ); if (charts.recovery) charts.recovery.destroy(); charts.recovery = new Chart(recoveryCtx, { type: 'bar', data: { labels: recoveryLabels, datasets: [{ label: 'Revenue Recovered', data: recoveryData, backgroundColor: '#3b82f6' }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: 'Recovery by Email Step' } } } }); // Funnel chart const funnelCtx = document.getElementById('funnelChart').getContext('2d'); const metrics = calculateMetrics(); if (charts.funnel) charts.funnel.destroy(); charts.funnel = new Chart(funnelCtx, { type: 'doughnut', data: { labels: ['Still Abandoned', 'Recovered', 'Emailed (Not Recovered)'], datasets: [{ data: [ cartData.filter(c => c.status === 'Abandoned').length, metrics.recoveredCarts, cartData.filter(c => c.status === 'Emailed').length ], backgroundColor: ['#ef4444', '#22c55e', '#f97316']}] }, options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: 'Cart Status Funnel' } } } }); }; const renderStrategyConfig = () => { const configContent = document.getElementById('content-strategy'); if (!configContent) return; const strategyHtml = appData.strategy.map((step, index) => `

Email #${index + 1}

`).join(''); configContent.innerHTML = `
${strategyHtml}
`; attachStrategyListeners(); }; const attachStrategyListeners = () => { document.querySelectorAll('.strategy-input').forEach(input => { input.addEventListener('change', (e) => { const { index, prop } = e.target.dataset; const value = e.target.type === 'number' ? parseFloat(e.target.value) : e.target.value; appData.strategy[index][prop] = value; alert('Strategy updated. Note: Run simulation on the Data tab to see effects.'); }); }); }; const renderCartData = () => { const dataContent = document.getElementById('content-data'); if (!dataContent) return; const getStatusBadge = (status) => { const colors = { Abandoned: 'bg-yellow-100 text-yellow-800', Emailed: 'bg-orange-100 text-orange-800', Recovered: 'bg-green-100 text-green-800' }; return `${status}`; }; const tableRows = cartData.map(cart => ` ${cart.email} ${formatCurrency(cart.value)} ${cart.items} ${getStatusBadge(cart.status)} `).join(''); dataContent.innerHTML = `

Abandoned Carts Data

${tableRows}
Customer Email Cart Value Status
Note: This is sample data. Running the simulation will attempt to recover carts with 'Abandoned' status.
`; document.getElementById('run-simulation-btn').addEventListener('click', runRecoverySimulation); lucide.createIcons(); }; const generatePdf = () => { loadingOverlay.style.display = 'flex'; const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-content-area'); const pdfHeader = document.getElementById('pdf-header'); document.getElementById('pdf-generated-date').textContent = new Date().toLocaleDateString('en-US'); pdfHeader.classList.remove('hidden'); html2canvas(pdfContent, { scale: 2, useCORS: true, logging: false }) .then(canvas => { pdfHeader.classList.add('hidden'); const imgData = canvas.toDataURL('image/jpeg', 0.95); const pdf = new jsPDF({ orientation: 'landscape', unit: 'px', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const imgProps = pdf.getImageProperties(imgData); const imgHeight = (imgProps.height * pdfWidth) / imgProps.width; pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, imgHeight); pdf.save('Cart-Recovery-Report.pdf'); loadingOverlay.style.display = 'none'; }).catch(err => { console.error("PDF generation failed:", err); pdfHeader.classList.add('hidden'); loadingOverlay.style.display = 'none'; alert('An error occurred generating the PDF.'); }); }; // --- TAB NAVIGATION & INITIALIZATION --- const initializeTabs = () => { const tabsContainer = document.getElementById('tabs-container'); const prevTabBtn = document.getElementById('prev-tab-btn'); const nextTabBtn = document.getElementById('next-tab-btn'); let activeTabIndex = 0; const tabs = [ { name: 'Recovery Dashboard', id: 'dashboard' }, { name: 'Bot Strategy', id: 'strategy' }, { name: 'Abandoned Carts Data', id: 'data' } ]; tabsContainer.innerHTML = tabs.map(t => ``).join(''); mainContent.innerHTML = tabs.map(t => `
`).join(''); const tabButtons = tabsContainer.querySelectorAll('.tab-btn'); const tabContents = mainContent.querySelectorAll('.tab-content'); const switchTab = (index) => { activeTabIndex = index; tabButtons.forEach((btn, i) => btn.classList.toggle('active', i === index)); tabContents.forEach((content, i) => content.classList.toggle('hidden', i !== index)); prevTabBtn.disabled = activeTabIndex === 0; nextTabBtn.disabled = activeTabIndex === tabs.length - 1; }; tabButtons.forEach((btn, index) => btn.addEventListener('click', () => switchTab(index))); prevTabBtn.addEventListener('click', () => { if (activeTabIndex > 0) switchTab(activeTabIndex - 1); }); nextTabBtn.addEventListener('click', () => { if (activeTabIndex < tabs.length - 1) switchTab(activeTabIndex + 1); }); switchTab(0); renderDashboard(); renderStrategyConfig(); renderCartData(); }; initializeTabs(); });
Scroll to Top