Online Seasonal Discount Scheduler

Seasonal Discount Scheduler

Plan your promotional calendar for the year.

Campaign Types

Define the campaigns you want to schedule.

Scheduled Discounts

${startDate} - ${endDate}

`; scheduledList.appendChild(div); }); } // --- CALENDAR GENERATION --- function generateCalendar(year) { calendarContainer.innerHTML = ''; const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; for (let month = 0; month < 12; month++) { const monthContainer = document.createElement('div'); monthContainer.className = 'p-3 bg-white border border-amber-100 rounded-lg'; const firstDay = new Date(year, month, 1); const lastDay = new Date(year, month + 1, 0); const daysInMonth = lastDay.getDate(); let monthHTML = `

${months[month]} ${year}

Sun
Mon
Tue
Wed
Thu
Fri
Sat
`; // Add blank days for the first week for (let i = 0; i < firstDay.getDay(); i++) { monthHTML += `
`; } // Add days of the month for (let day = 1; day <= daysInMonth; day++) { const date = new Date(year, month, day); const campaignsOnThisDay = scheduledCampaigns.filter(s => { const start = new Date(s.start); const end = new Date(s.end); start.setHours(0,0,0,0); end.setHours(23,59,59,999); return date >= start && date <= end; }); let campaignBarsHTML = ''; if (campaignsOnThisDay.length > 0) { const campaignType = campaignTypes.find(ct => ct.id === campaignsOnThisDay[0].typeId); if (campaignType) { campaignBarsHTML = `
${campaignType.name} (${campaignType.discount}%)
`; } } monthHTML += `
${day} ${campaignBarsHTML}
`; } monthHTML += `
`; // Close calendar-grid monthContainer.innerHTML = monthHTML; calendarContainer.appendChild(monthContainer); } } // --- PDF GENERATION --- function downloadPDF() { const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'mm', 'a4'); const date = new Date().toLocaleString(); const currentYear = yearSelector.value; doc.setFillColor(154, 52, 18); // Orange 800 doc.rect(0, 0, doc.internal.pageSize.getWidth(), 30, 'F'); doc.setFont('helvetica', 'bold'); doc.setFontSize(22); doc.setTextColor(255, 255, 255); doc.text(`Discount Schedule for ${currentYear}`, 15, 18); if (scheduledCampaigns.length === 0) { doc.setFontSize(12); doc.setTextColor(100); doc.text("No discounts have been scheduled for this year.", 15, 45); } else { const sorted = [...scheduledCampaigns].sort((a,b) => new Date(a.start) - new Date(b.start)); const tableBody = sorted.map(s => { const type = campaignTypes.find(c => c.id === s.typeId); return [ type ? type.name : 'Unknown', type ? `${type.discount}%` : 'N/A', new Date(s.start).toLocaleDateString(), new Date(s.end).toLocaleDateString() ]; }); doc.autoTable({ startY: 40, head: [['Campaign Name', 'Discount', 'Start Date', 'End Date']], body: tableBody, theme: 'grid', headStyles: { fillColor: [249, 115, 22] } // Orange 500 }); } doc.setFontSize(10); doc.setTextColor(150); doc.text(`Report generated on: ${date}`, 15, doc.internal.pageSize.getHeight() - 10); doc.save(`discount_schedule_${currentYear}.pdf`); } // --- EVENT LISTENERS --- yearSelector.addEventListener('change', () => { year = parseInt(yearSelector.value) || new Date().getFullYear(); generateCalendar(year); }); addCampaignTypeBtn.addEventListener('click', () => openCampaignModal()); modalSaveBtn.addEventListener('click', saveCampaignType); modalCancelBtn.addEventListener('click', closeCampaignModal); campaignTypeList.addEventListener('click', (e) => { const editBtn = e.target.closest('.edit-type-btn'); const deleteBtn = e.target.closest('.delete-type-btn'); if (editBtn) { const campaign = campaignTypes.find(c => c.id == editBtn.dataset.id); if (campaign) openCampaignModal(campaign); } if (deleteBtn) { deleteCampaignType(deleteBtn.dataset.id); } }); // This is a bit of a trick for dynamic content. We can have a button on the calendar to trigger scheduling. // For now, let's add a button in the scheduled list header const scheduleBtnHtml = ``; document.querySelector('#scheduled-list').parentElement.querySelector('h3').style.position = 'relative'; document.querySelector('#scheduled-list').parentElement.querySelector('h3').insertAdjacentHTML('beforeend', scheduleBtnHtml); document.getElementById('open-schedule-modal-btn').addEventListener('click', openScheduleModal); scheduleAddBtn.addEventListener('click', addScheduledCampaign); scheduleCancelBtn.addEventListener('click', closeScheduleModal); scheduledList.addEventListener('click', (e) => { const deleteBtn = e.target.closest('.delete-scheduled-btn'); if(deleteBtn) { deleteScheduledCampaign(deleteBtn.dataset.id); } }); pdfBtn.addEventListener('click', downloadPDF); // --- INITIALIZATION --- function initialize() { // Pre-populate with sample USA data campaignTypes = [ { id: 1, name: 'Presidents\' Day Sale', discount: 15, color: '#3b82f6' }, { id: 2, name: 'Summer Kickoff', discount: 20, color: '#f97316' }, { id: 3, name: 'Black Friday', discount: 50, color: '#1f2937' }, { id: 4, name: 'Holiday Special', discount: 25, color: '#dc2626' } ]; scheduledCampaigns = [ { id: 101, typeId: 1, start: '2025-02-14', end: '2025-02-17' }, { id: 102, typeId: 2, start: '2025-05-23', end: '2025-05-31' }, { id: 103, typeId: 3, start: '2025-11-28', end: '2025-11-30' }, { id: 104, typeId: 4, start: '2025-12-15', end: '2025-12-24' }, ]; yearSelector.value = year; renderAll(); } initialize(); });
Scroll to Top