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)

Avg. Sleep Quality

${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