Online Time Optimization Tool

Online Time Optimization Tool

Coordinate schedules, convert time zones, and plan meetings efficiently across the globe.

----------

`; clocksContainer.appendChild(card); }); updateAllClocks(); updateDownloadButtonState(); } function updateAllClocks() { const now = new Date(); const meetingDateTime = getMeetingDateTime(); document.querySelectorAll('[data-role="current-time"]').forEach(el => { const timezone = el.dataset.timezone; if (!timezone) return; el.textContent = now.toLocaleTimeString('en-US', { timeZone: timezone, hour12: false }); }); document.querySelectorAll('[data-role="current-date"]').forEach(el => { const timezone = el.dataset.timezone; if (!timezone) return; el.textContent = now.toLocaleDateString('en-US', { timeZone: timezone, weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); }); if (meetingDateTime) { updateMeetingTimes(meetingDateTime); } } function getMeetingDateTime() { if (meetingDateInput.value && meetingTimeInput.value) { return new Date(`${meetingDateInput.value}T${meetingTimeInput.value}`); } return null; } function updateMeetingTimes(dateTime) { if (!dateTime || isNaN(dateTime)) return; document.querySelectorAll('[data-role="meeting-time"]').forEach(el => { const timezone = el.dataset.timezone; if (!timezone) return; el.textContent = dateTime.toLocaleTimeString('en-US', { timeZone: timezone, hour: '2-digit', minute: '2-digit', hour12: true }); }); document.querySelectorAll('[data-role="meeting-date"]').forEach(el => { const timezone = el.dataset.timezone; if (!timezone) return; el.textContent = dateTime.toLocaleDateString('en-US', { timeZone: timezone, weekday: 'short', month: 'short', day: 'numeric' }); }); } // --- TIME CONVERTER LOGIC --- function runConversion() { const fromTz = fromCityInput.dataset.timezone; const toTz = toCityInput.dataset.timezone; const fromDate = fromDateInput.value; const fromTime = fromTimeInput.value; if (!fromTz || !toTz || !fromDate || !fromTime) { conversionResult.classList.add('hidden'); return; } try { const fromDateTimeStr = `${fromDate}T${fromTime}`; const localDate = new Date(fromDateTimeStr); const targetDate = new Date(localDate.toLocaleString("en-US", {timeZone: toTz})); const sourceDate = new Date(localDate.toLocaleString("en-US", {timeZone: fromTz})); const timeDiff = (targetDate.getTime() - sourceDate.getTime()); const convertedDate = new Date(localDate.getTime() + timeDiff); resultTime.textContent = convertedDate.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true }); resultDate.textContent = convertedDate.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); conversionResult.classList.remove('hidden'); } catch (e) { console.error("Error during time conversion:", e); conversionResult.classList.add('hidden'); } } // --- PDF GENERATION (NEW VISUAL REPORT) --- async function generatePdf() { const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const meetingDateTime = getMeetingDateTime(); if (!meetingDateTime || selectedLocations.length === 0) { // In a real app, you'd show a modal, not an alert. For this context, console log is fine. console.error("Please select locations and a meeting time first."); return; } const pageHeight = doc.internal.pageSize.height; const pageWidth = doc.internal.pageSize.width; const margin = 40; let yPos = margin + 20; // --- PDF Header --- doc.setFont("helvetica", "bold"); doc.setFontSize(24); doc.setTextColor("#2d3748"); // Dark Gray doc.text("Optimized Meeting Schedule", pageWidth / 2, yPos, { align: "center" }); yPos += 25; doc.setFont("helvetica", "normal"); doc.setFontSize(12); doc.setTextColor("#718096"); // Lighter Gray const meetingDateStr = meetingDateTime.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); const meetingTimeStr = meetingDateTime.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true }); doc.text(`Primary Meeting Time: ${meetingDateStr} at ${meetingTimeStr} (Your Local Time)`, pageWidth / 2, yPos, { align: "center" }); yPos += 45; // --- PDF Main Content --- selectedLocations.forEach((loc, index) => { if (yPos > pageHeight - 100) { // Page break logic doc.addPage(); yPos = margin; } const localMeetingTime = meetingDateTime.toLocaleTimeString('en-US', { timeZone: loc.timezone, hour: '2-digit', minute: '2-digit', hour12: true }); const localMeetingDate = meetingDateTime.toLocaleDateString('en-US', { timeZone: loc.timezone, weekday: 'short', month: 'short', day: 'numeric' }); const localHour = parseInt(meetingDateTime.toLocaleTimeString('en-US', { timeZone: loc.timezone, hour: '2-digit', hour12: false }), 10); // --- Time of Day Visualization --- let timeOfDayColor, timeOfDayText; if (localHour >= 6 && localHour < 12) { timeOfDayColor = "#FBBF24"; // Amber 400 timeOfDayText = "Morning"; } else if (localHour >= 12 && localHour < 18) { timeOfDayColor = "#3B82F6"; // Blue 500 timeOfDayText = "Afternoon"; } else if (localHour >= 18 && localHour < 22) { timeOfDayColor = "#6366F1"; // Indigo 500 timeOfDayText = "Evening"; } else { timeOfDayColor = "#4B5563"; // Gray 600 timeOfDayText = "Night"; } // --- Draw Entry --- doc.setFillColor("#F9FAFB"); // Gray 50 doc.setDrawColor("#E5E7EB"); // Gray 200 doc.roundedRect(margin, yPos, pageWidth - (margin * 2), 60, 5, 5, 'FD'); // Location Info doc.setFont("helvetica", "bold"); doc.setFontSize(14); doc.setTextColor("#1F2937"); // Gray 800 doc.text(`${loc.city}, ${loc.country}`, margin + 20, yPos + 25); // Meeting Time Info doc.setFont("helvetica", "normal"); doc.setFontSize(12); doc.setTextColor("#4B5563"); // Gray 600 doc.text(`${localMeetingTime} - ${localMeetingDate}`, margin + 20, yPos + 45); // Time of Day Visualization on the right doc.setFillColor(timeOfDayColor); doc.roundedRect(pageWidth - margin - 100, yPos + 15, 80, 30, 15, 15, 'F'); doc.setFont("helvetica", "bold"); doc.setFontSize(10); doc.setTextColor("#FFFFFF"); // White text on the color block doc.text(timeOfDayText, pageWidth - margin - 60, yPos + 34, { align: 'center' }); yPos += 75; // Increment y position for the next entry }); // --- PDF Footer --- const footerY = pageHeight - 20; doc.setFontSize(8); doc.setTextColor("#9CA3AF"); // Gray 400 doc.text(`Report generated on ${new Date().toLocaleDateString()}`, margin, footerY); doc.text("Online Time Optimization Tool", pageWidth - margin, footerY, { align: "right" }); // --- Save the PDF --- const fileName = `Optimized_Schedule_${meetingDateTime.toISOString().split('T')[0]}.pdf`; doc.save(fileName); } // --- TAB NAVIGATION LOGIC --- function switchTab(tabIndex) { currentTabIndex = tabIndex; tabsContainer.querySelectorAll('button').forEach((btn, index) => { btn.classList.toggle('tab-active', index === tabIndex); btn.classList.toggle('tab-inactive', index !== tabIndex); }); tabContents.forEach((content, index) => { content.classList.toggle('hidden', index !== tabIndex); }); updateButtonStates(); } function updateButtonStates() { prevBtn.disabled = currentTabIndex === 0; nextBtn.disabled = currentTabIndex === tabs.length - 1; prevBtn.classList.toggle('opacity-50', prevBtn.disabled); nextBtn.classList.toggle('opacity-50', nextBtn.disabled); } function updateDownloadButtonState() { downloadPdfBtn.disabled = selectedLocations.length === 0; } // --- EVENT LISTENERS --- meetingDateInput.addEventListener('change', () => updateAllClocks()); meetingTimeInput.addEventListener('change', () => updateAllClocks()); clocksContainer.addEventListener('click', function(e) { if (e.target && e.target.classList.contains('remove-btn')) { const timezone = e.target.dataset.timezone; removeLocation(timezone); } }); downloadPdfBtn.addEventListener('click', generatePdf); tabsContainer.querySelectorAll('button').forEach((btn, index) => { btn.addEventListener('click', () => switchTab(index)); }); prevBtn.addEventListener('click', () => { if (currentTabIndex > 0) switchTab(currentTabIndex - 1); }); nextBtn.addEventListener('click', () => { if (currentTabIndex < tabs.length - 1) switchTab(currentTabIndex + 1); }); [fromCityInput, toCityInput, fromDateInput, fromTimeInput].forEach(el => { el.addEventListener('change', runConversion); el.addEventListener('input', runConversion); }); document.addEventListener('click', function (e) { if (!e.target.matches('#cityInput, #fromCity, #toCity')) { closeAllLists(); } }); // --- RUN INITIALIZATION --- if (cityInput && meetingDateInput && meetingTimeInput && clocksContainer) { initialize(); } else { console.error("A critical element for the Time Optimization Tool was not found."); } });
Scroll to Top