Issue Date: ${formatDate(new Date(appData.inputs.issueDate + 'T00:00:00Z'))}
Terms: ${appData.inputs.paymentTerm === 'custom' ? `${appData.inputs.customDays} days` : `Net ${appData.inputs.paymentTerm.replace('net', '')}`}
Adjustment: ${adjustmentApplied}
`;
attachCalculatorListeners();
};
const renderHolidayConfig = () => {
const configContent = document.getElementById('content-holiday-config');
if (!configContent) return;
const holidaysByYear = appData.config.holidays.reduce((acc, holiday) => {
const year = holiday.date.substring(0, 4);
if (!acc[year]) acc[year] = [];
acc[year].push(holiday);
return acc;
}, {});
let holidaysHtml = Object.keys(holidaysByYear).sort().map(year => {
const yearHtml = holidaysByYear[year].map((h, i) => `
`).join('');
return `
${year}
${yearHtml}
`;
}).join('');
configContent.innerHTML = `
Manage Public Holidays
Holidays are used to adjust due dates that fall on a non-business day.
${holidaysHtml}
`;
lucide.createIcons();
attachConfigListeners();
};
// --- EVENT HANDLERS ---
const attachCalculatorListeners = () => {
const updateAndRecalculate = () => {
appData.inputs.issueDate = document.getElementById('issue-date').value;
appData.inputs.paymentTerm = document.getElementById('payment-term').value;
appData.inputs.customDays = document.getElementById('custom-days').value;
appData.inputs.weekendRule = document.querySelector('input[name="weekend-rule"]:checked').value;
calculateDueDate();
renderCalculator();
};
document.getElementById('issue-date').addEventListener('change', updateAndRecalculate);
document.getElementById('payment-term').addEventListener('change', (e) => {
document.getElementById('custom-days').classList.toggle('hidden', e.target.value !== 'custom');
updateAndRecalculate();
});
document.getElementById('custom-days').addEventListener('input', updateAndRecalculate);
document.querySelectorAll('input[name="weekend-rule"]').forEach(radio => radio.addEventListener('change', updateAndRecalculate));
document.getElementById('download-pdf-btn').addEventListener('click', generatePdf);
};
const attachConfigListeners = () => {
document.getElementById('add-holiday-btn').addEventListener('click', () => {
const dateInput = document.getElementById('new-holiday-date');
const nameInput = document.getElementById('new-holiday-name');
if (dateInput.value && nameInput.value) {
if (!appData.config.holidays.some(h => h.date === dateInput.value)) {
appData.config.holidays.push({ date: dateInput.value, name: nameInput.value });
appData.config.holidays.sort((a,b) => new Date(a.date) - new Date(b.date));
renderHolidayConfig();
calculateDueDate(); // Recalculate as holidays changed
} else {
alert('This date is already in the holiday list.');
}
}
});
document.querySelectorAll('.remove-holiday-btn').forEach(btn => btn.addEventListener('click', e => {
const dateToRemove = e.currentTarget.dataset.date;
appData.config.holidays = appData.config.holidays.filter(h => h.date !== dateToRemove);
renderHolidayConfig();
calculateDueDate();
}));
document.querySelectorAll('.holiday-name-input').forEach(input => input.addEventListener('change', e => {
const dateToUpdate = e.target.dataset.date;
const holiday = appData.config.holidays.find(h => h.date === dateToUpdate);
if(holiday) holiday.name = e.target.value;
}));
};
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: 'portrait', unit: 'px', format: [canvas.width * 0.5, canvas.height * 0.5] });
pdf.addImage(imgData, 'JPEG', 0, 0, canvas.width * 0.5, canvas.height * 0.5);
pdf.save('Invoice-DueDate-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 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: 'Due Date Calculator', id: 'calculator' },
{ name: 'Holiday Configuration', id: 'holiday-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));
});
renderCalculator();
renderHolidayConfig();
switchTab(0);
};
initializeUI();
prevTabBtn.addEventListener('click', () => { if (activeTabIndex > 0) switchTab(activeTabIndex - 1); });
nextTabBtn.addEventListener('click', () => { if (activeTabIndex < tabIdentifiers.length - 1) switchTab(activeTabIndex + 1); });
});