// Initialize app let currentView = 'dashboardView'; let selectedMood = null; let charts = {}; // View management function showView(viewId) { // Hide all views document.querySelectorAll('.view').forEach(view => { view.classList.add('hidden'); }); // Show selected view document.getElementById(viewId).classList.remove('hidden'); // Update navigation document.querySelectorAll('.nav-btn').forEach(btn => { btn.classList.remove('active'); if (btn.dataset.view === viewId) { btn.classList.add('active'); } }); currentView = viewId; // Initialize charts for specific views if (viewId === 'strainView') { initializeStrainCharts(); } else if (viewId === 'sleepView') { initializeSleepCharts(); } else if (viewId === 'recoveryView') { initializeRecoveryChart(); } // Re-initialize feather icons feather.replace(); } function showJournal() { showView('journalView'); } function showProfile() { // Placeholder for profile modal alert('Profile feature coming soon!'); } // Initialize charts function initializeStrainCharts() { // Strain Gauge const strainGaugeCtx = document.getElementById('strainGauge'); if (strainGaugeCtx && !charts.strainGauge) { charts.strainGauge = new Chart(strainGaugeCtx, { type: 'doughnut', data: { datasets: [{ data: [41, 59], backgroundColor: ['#eab308', '#fef3c7'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '70%', plugins: { legend: { display: false }, tooltip: { enabled: false } } } }); } // Hourly Strain Chart const hourlyStrainCtx = document.getElementById('hourlyStrainChart'); if (hourlyStrainCtx && !charts.hourlyStrain) { const hours = Array.from({length: 24}, (_, i) => `${i}:00`); const strainData = [ 2, 2, 1, 1, 2, 3, 8, 12, 5, 4, 3, 5, 8, 6, 4, 3, 4, 7, 3, 2, 2, 2, 1, 1 ]; charts.hourlyStrain = new Chart(hourlyStrainCtx, { type: 'line', data: { labels: hours, datasets: [{ label: 'Strain', data: strainData, borderColor: '#eab308', backgroundColor: 'rgba(234, 179, 8, 0.1)', fill: true, tension: 0.4, pointRadius: 2, pointHoverRadius: 4 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, max: 21, grid: { color: 'rgba(0, 0, 0, 0.05)' } }, x: { grid: { display: false } } }, plugins: { legend: { display: false } } } }); } } function initializeSleepCharts() { // Sleep Stages Chart const sleepStagesCtx = document.getElementById('sleepStagesChart'); if (sleepStagesCtx && !charts.sleepStages) { const timeLabels = Array.from({length: 24}, (_, i) => { const hour = i < 10 ? `0${i}:00` : `${i}:00`; return hour; }); const sleepData = timeLabels.map((_, i) => { if (i < 22 || i > 23) return 0; if (i === 22) return 2; if (i === 23) return 3; return i % 4 + 1; }); charts.sleepStages = new Chart(sleepStagesCtx, { type: 'bar', data: { labels: timeLabels, datasets: [{ label: 'Sleep Stage', data: sleepData, backgroundColor: sleepData.map(value => { if (value === 0) return '#e5e7eb'; if (value === 1) return '#ddd6fe'; if (value === 2) return '#93c5fd'; if (value === 3) return '#60a5fa'; return '#8b5cf6'; }), borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { display: false, max: 4 }, x: { ticks: { maxTicksLimit: 12 }, grid: { display: false } } }, plugins: { legend: { display: false }, tooltip: { callbacks: { label: function(context) { const stages = ['', 'Light Sleep', 'Deep Sleep', 'REM Sleep', 'Awake']; return stages[context.parsed.y] || 'Awake'; } } } } } }); } } function initializeRecoveryChart() { // Recovery Ring Chart const recoveryRingCtx = document.getElementById('recoveryRing'); if (recoveryRingCtx && !charts.recoveryRing) { charts.recoveryRing = new Chart(recoveryRingCtx, { type: 'doughnut', data: { datasets: [{ data: [78, 22], backgroundColor: ['#10b981', '#d1fae5'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '75%', plugins: { legend: { display: false }, tooltip: { enabled: false } } } }); } } // Journal functionality document.addEventListener('DOMContentLoaded', function() { // Mood buttons document.querySelectorAll('.mood-btn').forEach(btn => { btn.addEventListener('click', function() { document.querySelectorAll('.mood-btn').forEach(b => b.classList.remove('selected')); this.classList.add('selected'); selectedMood = parseInt(this.dataset.mood); }); }); // Energy slider const energySlider = document.getElementById('energyLevel'); const energyValue = document.getElementById('energyValue'); if (energySlider && energyValue) { energySlider.addEventListener('input', function() { energyValue.textContent = this.value; }); } // Stress slider const stressSlider = document.getElementById('stressLevel'); const stressValue = document.getElementById('stressValue'); if (stressSlider && stressValue) { stressSlider.addEventListener('input', function() { stressValue.textContent = this.value; }); } // Journal form submission const journalForm = document.getElementById('journalForm'); if (journalForm) { journalForm.addEventListener('submit', function(e) { e.preventDefault(); const formData = { mood: selectedMood, energy: document.getElementById('energyLevel').value, stress: document.getElementById('stressLevel').value, activities: Array.from(document.querySelectorAll('.activity-checkbox:checked')).map(cb => cb.value), nutrition: Array.from(document.querySelectorAll('.nutrition-checkbox:checked')).map(cb => cb.value), notes: document.getElementById('journalNotes').value, timestamp: new Date().toISOString() }; // Save to localStorage (in real app, would send to server) let journalEntries = JSON.parse(localStorage.getItem('journalEntries') || '[]'); journalEntries.push(formData); localStorage.setItem('journalEntries', JSON.stringify(journalEntries)); // Show success message showNotification('Journal entry saved successfully!'); // Reset form journalForm.reset(); document.querySelectorAll('.mood-btn').forEach(b => b.classList.remove('selected')); selectedMood = null; // Go back to dashboard after a short delay setTimeout(() => showView('dashboardView'), 1500); }); } }); // Notification system function showNotification(message, type = 'success') { const notification = document.createElement('div'); notification.className = `fixed top-20 left-4 right-4 max-w-md mx-auto px-4 py-3 rounded-lg shadow-lg z-50 transform transition-all duration-300 ${ type === 'success' ? 'bg-emerald-500 text-white' : 'bg-red-500 text-white' }`; notification.innerHTML = `
${message}
`; document.body.appendChild(notification); feather.replace(); // Animate in setTimeout(() => { notification.classList.add('translate-y-0'); }, 100); // Remove after 3 seconds setTimeout(() => { notification.classList.add('translate-y-full', 'opacity-0'); setTimeout(() => notification.remove(), 300); }, 3000); } // Simulate real-time data updates function updateMetrics() { // Update heart rate with slight variation const heartRateElements = document.querySelectorAll('[data-metric="heart-rate"]'); heartRateElements.forEach(el => { const currentRate = parseInt(el.textContent); const variation = Math.floor(Math.random() * 3) - 1; const newRate = Math.max(50, Math.min(60, currentRate + variation)); el.textContent = newRate + ' bpm'; }); } // Initialize app on load window.addEventListener('load', function() { showView('dashboardView'); // Update metrics every 30 seconds setInterval(updateMetrics, 30000); }); // Handle page visibility changes document.addEventListener('visibilitychange', function() { if (!document.hidden) { // Refresh data when page becomes visible again if (currentView === 'strainView') { initializeStrainCharts(); } else if (currentView === 'sleepView') { initializeSleepCharts(); } else if (currentView === 'recoveryView') { initializeRecoveryChart(); } } }); // Touch gestures for mobile let touchStartX = 0; let touchEndX = 0; document.addEventListener('touchstart', function(e) { touchStartX = e.changedTouches[0].screenX; }); document.addEventListener('touchend', function(e) { touchEndX = e.changedTouches[0].screenX; handleSwipe(); }); function handleSwipe() { const swipeThreshold = 50; const diff = touchStartX - touchEndX; if (Math.abs(diff) > swipeThreshold) { const views = ['dashboardView', 'strainView', 'sleepView', 'recoveryView', 'journalView']; const currentIndex = views.indexOf(currentView); if (diff > 0 && currentIndex < views.length - 1) { // Swipe left - next view showView(views[currentIndex + 1]); } else if (diff < 0 && currentIndex > 0) { // Swipe right - previous view showView(views[currentIndex - 1]); } } }