Online Smart Calendar Sync Tool

Smart Calendar Sync Tool

Connect and manage your calendars in one place.

Connect Your Calendars

Simulate connecting your calendar accounts to begin. No actual login is required.

Google Logo

Google Calendar

Outlook Logo

Outlook Calendar

No events to display. Connect accounts and check sync rules.

`; return; } let lastDate = null; events.forEach(event => { const eventDate = event.start.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); if (eventDate !== lastDate) { const dateHeader = document.createElement('h3'); dateHeader.className = 'text-lg font-semibold text-gray-800 mt-4 pt-4 border-t'; dateHeader.textContent = eventDate; calendarView.appendChild(dateHeader); lastDate = eventDate; } const eventCard = document.createElement('div'); const sourceColor = event.source === 'google' ? 'border-l-red-500' : 'border-l-blue-500'; const sourceBg = event.source === 'google' ? 'bg-red-50' : 'bg-blue-50'; eventCard.className = `p-4 rounded-lg border border-l-4 ${sourceColor} ${sourceBg} flex items-center justify-between`; eventCard.innerHTML = `

${event.title}

${formatTime(event.start)} - ${formatTime(event.end)}

${event.source.charAt(0).toUpperCase() + event.source.slice(1)} `; calendarView.appendChild(eventCard); }); } function switchTab(tabName) { state.currentTab = tabName; tabPanes.forEach(pane => pane.classList.add('hidden')); document.getElementById(tabName).classList.remove('hidden'); tabBtns.forEach(btn => { if (btn.dataset.tab === tabName) { btn.classList.add('tab-active'); btn.classList.remove('tab-inactive'); } else { btn.classList.add('tab-inactive'); btn.classList.remove('tab-active'); } }); updateNavButtons(); if (tabName === 'calendar') { renderSyncedCalendar(); } } function updateNavButtons() { const tabs = ['accounts', 'rules', 'calendar']; const currentIndex = tabs.indexOf(state.currentTab); prevTabBtn.disabled = currentIndex === 0; nextTabBtn.disabled = currentIndex === tabs.length - 1; } function navigateTabs(direction) { const tabs = ['accounts', 'rules', 'calendar']; const currentIndex = tabs.indexOf(state.currentTab); const newIndex = currentIndex + direction; if (newIndex >= 0 && newIndex < tabs.length) { switchTab(tabs[newIndex]); } } // SECTION: UTILITY FUNCTIONS // ========================== function formatTime(date) { return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true }); } // SECTION: PDF GENERATION // ======================= function generatePDF() { const { jsPDF } = window.jspdf; const doc = new jsPDF(); const events = getSyncedEvents(); doc.setFont('helvetica', 'bold'); doc.setFontSize(22); doc.setTextColor('#1f2937'); doc.text('Synced Calendar Schedule', doc.internal.pageSize.getWidth() / 2, 20, { align: 'center' }); const reportDate = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }); doc.setFont('helvetica', 'normal'); doc.setFontSize(11); doc.setTextColor('#6b7280'); doc.text(`Generated on: ${reportDate}`, doc.internal.pageSize.getWidth() / 2, 28, { align: 'center' }); const tableColumn = ["Date", "Time", "Event Title", "Source"]; const tableRows = []; events.forEach(event => { const eventData = [ event.start.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }), `${formatTime(event.start)} - ${formatTime(event.end)}`, event.title, event.source.charAt(0).toUpperCase() + event.source.slice(1) ]; tableRows.push(eventData); }); doc.autoTable({ head: [tableColumn], body: tableRows, startY: 40, theme: 'grid', headStyles: { fillColor: [243, 244, 246], textColor: [31, 41, 55] } }); doc.save(`Synced_Schedule_${new Date().toISOString().split('T')[0]}.pdf`); } // SECTION: EVENT LISTENERS // ======================== function setupEventListeners() { tabBtns.forEach(btn => btn.addEventListener('click', () => switchTab(btn.dataset.tab))); prevTabBtn.addEventListener('click', () => navigateTabs(-1)); nextTabBtn.addEventListener('click', () => navigateTabs(1)); syncDirectionSelect.addEventListener('change', updateSyncRules); privacyRadios.forEach(radio => radio.addEventListener('change', updateSyncRules)); downloadPdfBtn.addEventListener('click', generatePDF); setupDynamicEventListeners(); } function setupDynamicEventListeners() { // For dynamically added/removed connect/disconnect buttons document.querySelectorAll('.connect-btn').forEach(btn => { btn.addEventListener('click', (e) => connectAccount(e.target.dataset.account)); }); document.querySelectorAll('.disconnect-btn').forEach(btn => { btn.addEventListener('click', (e) => disconnectAccount(e.target.dataset.account)); }); } // Initial application start renderAccountStatus(); setupEventListeners(); });
Scroll to Top