// Shared JavaScript across all pages class TimerManager { constructor() { this.timers = JSON.parse(localStorage.getItem('timers')) || []; this.selectedDuration = 3600; // Default 1 hour in seconds this.init(); } init() { this.bindEvents(); this.renderTimers(); this.startTimerUpdates(); } bindEvents() { // Modal controls document.getElementById('addTimerBtn').addEventListener('click', () => this.openModal()); document.getElementById('closeModal').addEventListener('click', () => this.closeModal()); // Duration selection document.querySelectorAll('.duration-btn').forEach(btn => { btn.addEventListener('click', (e) => this.selectDuration(e.target)); }); // Form submission document.getElementById('timerForm').addEventListener('submit', (e) => { e.preventDefault(); this.createTimer(true); }); // Add only button document.getElementById('addOnlyBtn').addEventListener('click', () => { this.createTimer(false); }); // Toggle controls document.getElementById('startImmediately').addEventListener('change', (e) => { this.toggleDelaySection(!e.target.checked); }); // Close modal on outside click document.getElementById('timerModal').addEventListener('click', (e) => { if (e.target.id === 'timerModal') { this.closeModal(); } }); } openModal() { const modal = document.getElementById('timerModal'); modal.classList.remove('hidden'); setTimeout(() => { modal.querySelector('div').classList.add('modal-open'); }, 10); } closeModal() { const modal = document.getElementById('timerModal'); modal.querySelector('div').classList.remove('modal-open'); setTimeout(() => { modal.classList.add('hidden'); this.resetForm(); }, 300); } selectDuration(button) { // Remove active class from all buttons document.querySelectorAll('.duration-btn').forEach(btn => { btn.classList.remove('bg-blue-500', 'text-white'); btn.classList.add('bg-slate-100', 'text-slate-700'); }); // Add active class to clicked button button.classList.remove('bg-slate-100', 'text-slate-700'); button.classList.add('bg-blue-500', 'text-white'); this.selectedDuration = parseInt(button.dataset.duration); } toggleDelaySection(immediate) { const delaySection = document.getElementById('delaySection'); const delayInput = document.getElementById('delayTime'); if (immediate) { delaySection.classList.add('opacity-50', 'pointer-events-none'); delayInput.disabled = true; } else { delaySection.classList.remove('opacity-50', 'pointer-events-none'); delayInput.disabled = false; } } resetForm() { document.getElementById('timerForm').reset(); document.getElementById('delayTime').disabled = false; document.getElementById('delaySection').classList.remove('opacity-50', 'pointer-events-none'); // Reset duration buttons to default document.querySelectorAll('.duration-btn').forEach(btn => { btn.classList.remove('bg-blue-500', 'text-white'); btn.classList.add('bg-slate-100', 'text-slate-700'); }); // Set first duration button as active const firstBtn = document.querySelector('.duration-btn'); firstBtn.classList.remove('bg-slate-100', 'text-slate-700'); firstBtn.classList.add('bg-blue-500', 'text-white'); this.selectedDuration = 3600; } createTimer(startImmediately) { const title = document.getElementById('timerTitle').value.trim(); const delayMinutes = document.getElementById('delayTime').value; const addWithoutStart = document.getElementById('addWithoutStart').checked; if (!title) { alert('Please enter a timer title'); return; } const timer = { id: Date.now().toString(), title: title, duration: this.selectedDuration, delay: parseInt(delayMinutes) * 60, // Convert to seconds status: addWithoutStart ? 'paused' : (startImmediately ? 'delayed' : 'paused'), startTime: startImmediately ? Date.now() : null, remaining: this.selectedDuration, createdAt: Date.now() }; this.timers.push(timer); this.saveTimers(); this.renderTimers(); this.closeModal(); // If starting immediately and no delay, begin countdown if (startImmediately && !addWithoutStart && delayMinutes === '0') { timer.status = 'running'; timer.startTime = Date.now(); } } startTimer(timerId) { const timer = this.timers.find(t => t.id === timerId); if (timer) { timer.status = timer.delay > 0 ? 'delayed' : 'running'; timer.startTime = Date.now(); this.saveTimers(); this.renderTimers(); } } deleteTimer(timerId) { this.timers = this.timers.filter(t => t.id !== timerId); this.saveTimers(); this.renderTimers(); } updateTimerRemaining() { const now = Date.now(); this.timers.forEach(timer => { if (timer.status === 'running' && timer.startTime) { const elapsed = Math.floor((now - timer.startTime) / 1000); timer.remaining = Math.max(0, timer.duration - elapsed); if (timer.remaining === 0) { this.completeTimer(timer.id); } } else if (timer.status === 'delayed' && timer.startTime) { const elapsed = Math.floor((now - timer.startTime) / 1000); if (elapsed >= timer.delay) { timer.status = 'running'; timer.startTime = now; // Reset start time for actual countdown } }); this.renderTimers(); } completeTimer(timerId) { const timer = this.timers.find(t => t.id === timerId); if (timer) { timer.status = 'completed'; this.saveTimers(); this.renderTimers(); this.playAlertSound(); } } playAlertSound() { const audio = document.getElementById('alertSound'); audio.play().catch(e => console.log('Audio play failed:', e)); } formatTime(seconds) { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = seconds % 60; return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; } renderTimers() { const container = document.getElementById('timersContainer'); const emptyState = document.getElementById('emptyState'); if (this.timers.length === 0) { container.classList.add('hidden'); emptyState.classList.remove('hidden'); return; } container.classList.remove('hidden'); emptyState.classList.add('hidden'); container.innerHTML = this.timers.map(timer => this.createTimerHTML(timer)).join(''); // Re-bind events for dynamically created elements this.bindTimerEvents(); } createTimerHTML(timer) { const isCompleted = timer.status === 'completed'; const isPaused = timer.status === 'paused'; const isDelayed = timer.status === 'delayed'; let statusText = ''; let statusIcon = ''; let statusClass = ''; if (isCompleted) { statusText = 'Finished'; statusIcon = 'check-circle'; statusClass = 'bg-green-100 text-green-800'; } else if (isPaused) { statusText = 'Paused'; statusIcon = 'pause'; statusClass = 'bg-yellow-100 text-yellow-800'; } else if (isDelayed) { statusText = 'Delayed'; statusIcon = 'clock'; statusClass = 'bg-blue-100 text-blue-800'; } else { statusText = 'Running'; statusIcon = 'play'; statusClass = 'bg-blue-100 text-blue-800'; } return `