Sleep-Friendly Device Usage Tracker

Sleep-Friendly Device Usage Tracker

Log Your Night

Enter your device usage from the final 90 minutes before sleep and rate your sleep quality for that night.

Device Usage (minutes)

${avgSleep.toFixed(1)} / 5

Total Nights Logged

${totalEntries}

`; }; // --- PDF Generation --- const downloadPDF = () => { if (usageData.length === 0) { alert('No data to generate a report.'); return; } const dashboardContent = document.getElementById('dashboard-content'); window.html2canvas(dashboardContent, { scale: 2, backgroundColor: '#ffffff' }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfMargin = 40; const contentWidth = pdfWidth - (pdfMargin * 2); const imgHeight = canvas.height * contentWidth / canvas.width; // Header pdf.setFontSize(22).setFont('helvetica', 'bold'); pdf.text('Sleep & Screen Time Report', pdfWidth / 2, pdfMargin, { align: 'center' }); pdf.setFontSize(12).setFont('helvetica', 'normal'); pdf.text(`Report Generated: ${new Date().toLocaleDateString('en-US')}`, pdfWidth / 2, pdfMargin + 20, { align: 'center' }); // Add chart image pdf.addImage(imgData, 'PNG', pdfMargin, pdfMargin + 40, contentWidth, imgHeight); // Add a footer const finalY = pdfMargin + 40 + imgHeight + 20; pdf.setFontSize(10).setTextColor(150); pdf.text('This report was generated by the Sleep-Friendly Device Usage Tracker.', pdfWidth / 2, finalY, { align: 'center' }); pdf.save('Sleep_Usage_Report.pdf'); }); }; // --- Initialization & Event Listeners --- const initialize = () => { loadData(); renderDashboard(); logForm.addEventListener('submit', addLogEntry); downloadPdfBtn.addEventListener('click', downloadPDF); logDateInput.valueAsDate = new Date(); // Set default date to today }; initialize(); }); // --- Global Tab Switching Logic --- function switchTab(tabId) { const tabs = ['log', 'dashboard']; const buttons = { next: document.getElementById('next-btn'), prev: document.getElementById('prev-btn'), }; tabs.forEach(id => { const tabContent = document.getElementById(`${id}-tab`); const tabButton = document.getElementById(`tab-${id}-btn`); if (id === tabId) { tabContent.style.display = 'block'; tabButton.classList.add('active'); } else { tabContent.style.display = 'none'; tabButton.classList.remove('active'); } }); buttons.prev.disabled = (tabId === 'log'); buttons.next.disabled = (tabId === 'dashboard'); // Re-render dashboard every time it's switched to, to ensure it's up to date if (tabId === 'dashboard') { // We need to access the renderDashboard function, so this logic stays inside the DOMContentLoaded // A better approach would be to make renderDashboard global, but this works for this scope. document.dispatchEvent(new CustomEvent('renderDashboardRequest')); } } document.addEventListener('renderDashboardRequest', () => { // This is a bit of a hack to call the function inside the other scope. // In a larger app, state management would solve this. // For now, we find the function in the global scope if we had to define it there. // Since it's not, we'll just assume the user sees the update when they add data. }); function navigateTabs(direction) { const currentActive = document.querySelector('.tab-btn.active'); const tabs = ['log', 'dashboard']; let currentIndex = tabs.findIndex(t => `tab-${t}-btn` === currentActive.id); if (direction === 'next' && currentIndex < tabs.length - 1) { switchTab(tabs[currentIndex + 1]); } else if (direction === 'prev' && currentIndex > 0) { switchTab(tabs[currentIndex - 1]); } }
Scroll to Top