Subscription Dashboard Subscription Dashboard Dashboard Data Configuration Current Subscription Metrics Total Subscribers Active Subscribers Inactive/Cancelled Monthly Recurring Revenue Churn Rate (Last 30 Days) Average Revenue Per User New Subscriptions (Last 30 Days) Cancelled Subscriptions (Last 30 Days) Download Dashboard as PDF Configure Subscription Data Total Subscribers: Active Subscribers: Monthly Recurring Revenue ($): New Subscriptions (Last 30 Days): Cancelled Subscriptions (Last 30 Days): Previous Next New Subscriptions (Last 30 Days) ${displayNewSubs.textContent} Cancelled Subscriptions (Last 30 Days) ${displayCancelledSubs.textContent} `; // Append to body temporarily to render for html2canvas document.body.appendChild(pdfContentWrapper); try { const canvas = await html2canvas(pdfContentWrapper, { scale: 2, // Increase scale for better resolution useCORS: true, // Required if images are from different origin (though we don't use images here) logging: false // Disable logging for cleaner console }); const imgData = canvas.toDataURL('image/png'); const pdf = new window.jspdf.jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' }); 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('Subscription_Dashboard.pdf'); } catch (error) { console.error('Error generating PDF:', error); // Provide a user-friendly message if PDF generation fails // Using alert as a fallback for critical error, as per instructions. // In a real production environment, a custom modal would be preferred. alert('Failed to generate PDF. Please try again.'); } finally { // Remove the temporary wrapper document.body.removeChild(pdfContentWrapper); } } // --- Event Listeners --- // Tab switching if (dashboardTabBtn) { dashboardTabBtn.addEventListener('click', function() { switchTab('dashboard'); }); } if (dataConfigTabBtn) { dataConfigTabBtn.addEventListener('click', function() { switchTab('dataConfig'); }); } // Navigation buttons if (prevTabBtn) { prevTabBtn.addEventListener('click', function() { if (currentActiveTab === 'dataConfig') { switchTab('dashboard'); } }); } if (nextTabBtn) { nextTabBtn.addEventListener('click', function() { if (currentActiveTab === 'dashboard') { switchTab('dataConfig'); } }); } // Input change listener (for real-time updates) const inputElements = [ totalSubscribersInput, activeSubscribersInput, mrrInput, newSubscriptionsLast30DaysInput, cancelledSubscriptionsLast30DaysInput ]; inputElements.forEach(input => { if (input) { input.addEventListener('input', function() { updateSubscriptionDataFromInputs(); renderDashboard(); // Update dashboard in real-time as inputs change }); } }); // PDF download button if (downloadPdfBtn) { downloadPdfBtn.addEventListener('click', downloadPdf); } // --- Initial Load --- populateInputFields(); // Populate inputs with initial data renderDashboard(); // Render dashboard with initial data switchTab('dashboard'); // Ensure dashboard tab is active on load });