Upcoming Payments
| Subscription |
Payment Date |
Amount |
Cycle |
${paymentsHtml}
`;
document.getElementById('download-pdf-btn').addEventListener('click', generatePdf);
};
const renderConfiguration = () => {
const configContent = document.getElementById('content-config');
if (!configContent) return;
const subsHtml = appData.subscriptions.map(sub => `
`).join('');
configContent.innerHTML = `
`;
lucide.createIcons();
document.getElementById('add-sub-btn').addEventListener('click', handleAddRow);
document.getElementById('config-form').addEventListener('submit', handleConfigSave);
document.querySelectorAll('.remove-sub-btn').forEach(btn => btn.addEventListener('click', (e) => e.currentTarget.closest('.sub-config-row').remove()));
};
const handleAddRow = () => {
const container = document.getElementById('subs-list-container');
const newRow = document.createElement('div');
newRow.className = 'sub-config-row grid grid-cols-12 gap-2 sm:gap-4 items-center is-new';
newRow.innerHTML = `
`;
container.appendChild(newRow);
lucide.createIcons();
newRow.querySelector('.remove-sub-btn').addEventListener('click', () => newRow.remove());
};
const handleConfigSave = (e) => {
e.preventDefault();
const newSubs = [];
let nextId = Math.max(...appData.subscriptions.map(s => s.id), 0) + 1;
document.querySelectorAll('.sub-config-row').forEach(row => {
const name = row.querySelector('[data-field="name"]').value;
const amount = parseFloat(row.querySelector('[data-field="amount"]').value);
if (!name || isNaN(amount)) return; // Skip invalid rows
const id = row.classList.contains('is-new') ? nextId++ : parseInt(row.dataset.id);
newSubs.push({
id, name, amount,
cycle: row.querySelector('[data-field="cycle"]').value,
nextBill: row.querySelector('[data-field="nextBill"]').value,
status: row.querySelector('[data-field="status"]').value,
});
});
appData.subscriptions = newSubs;
alert('Subscriptions saved!');
renderScheduler(); // Update dashboard with new data
renderConfiguration(); // Redraw config to sync state
};
const generatePdf = () => {
loadingOverlay.style.display = 'flex';
const { jsPDF } = window.jspdf;
const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' });
const activeSubs = appData.subscriptions.filter(s => s.status === 'active');
let totalMonthlyCost = activeSubs.reduce((sum, s) => {
if (s.cycle === 'monthly') return sum + s.amount;
if (s.cycle === 'quarterly') return sum + s.amount / 3;
if (s.cycle === 'annually') return sum + s.amount / 12;
return sum;
}, 0);
let y = 40;
pdf.setFontSize(18);
pdf.setFont('helvetica', 'bold');
pdf.text('Subscription Payment Report', pdf.internal.pageSize.getWidth() / 2, y, { align: 'center' });
y += 20;
pdf.setFontSize(10);
pdf.setFont('helvetica', 'normal');
pdf.text(`Generated on: ${new Date().toLocaleDateString()}`, pdf.internal.pageSize.getWidth() / 2, y, { align: 'center' });
y += 40;
pdf.autoTable({
startY: y,
body: [
[
{ content: 'Avg. Monthly Cost\n' + formatCurrency(totalMonthlyCost), styles: { halign: 'center', fontSize: 10, cellPadding: 10 } },
{ content: 'Total Annual Cost\n' + formatCurrency(totalMonthlyCost * 12), styles: { halign: 'center', fontSize: 10, cellPadding: 10 } },
{ content: 'Active Subscriptions\n' + activeSubs.length, styles: { halign: 'center', fontSize: 10, cellPadding: 10 } }
]
],
theme: 'plain',
styles: { font: 'helvetica', fontStyle: 'bold', lineWidth: 1, lineColor: [221, 221, 221] }
});
y = pdf.autoTable.previous.finalY + 30;
pdf.autoTable({
startY: y,
head: [['Subscription', 'Amount', 'Cycle', 'Next Bill Date', 'Status']],
body: appData.subscriptions.map(s => [s.name, formatCurrency(s.amount), s.cycle, formatDate(s.nextBill), s.status]),
theme: 'grid',
headStyles: { fillColor: [22, 163, 74] } // Green header
});
pdf.save(`Subscription-Report.pdf`);
loadingOverlay.style.display = 'none';
};
// --- TAB NAVIGATION & INITIALIZATION ---
const switchTab = (tabIndex) => {
activeTabIndex = tabIndex;
document.querySelectorAll('.tab-btn').forEach((btn, i) => btn.classList.toggle('active', i === tabIndex));
document.querySelectorAll('.tab-content').forEach((content, i) => content.classList.toggle('hidden', i !== tabIndex));
updateNavButtons();
};
const updateNavButtons = () => {
prevTabBtn.disabled = activeTabIndex === 0;
nextTabBtn.disabled = activeTabIndex === tabIdentifiers.length - 1;
};
const initializeUI = () => {
const tabs = [
{ name: 'Subscription Schedule', id: 'scheduler' },
{ name: 'Manage Subscriptions', id: 'config' }
];
tabIdentifiers = tabs.map(t => t.id);
tabsContainer.innerHTML = tabs.map(tab => `
`).join('');
mainContent.innerHTML = tabs.map(tab => `
`).join('');
tabs.forEach((tab, index) => {
document.getElementById(`tab-${tab.id}`).addEventListener('click', () => switchTab(index));
});
renderScheduler();
renderConfiguration();
switchTab(0);
lucide.createIcons();
};
initializeUI();
prevTabBtn.addEventListener('click', () => { if (activeTabIndex > 0) switchTab(activeTabIndex - 1); });
nextTabBtn.addEventListener('click', () => { if (activeTabIndex < tabIdentifiers.length - 1) switchTab(activeTabIndex + 1); });
});