Spaces:
Running
Running
| // Initialize app | |
| document.addEventListener('DOMContentLoaded', function() { | |
| initializeCharts(); | |
| setupEventListeners(); | |
| updateRealTimeData(); | |
| }); | |
| // Navigation | |
| function scrollToSection(sectionId) { | |
| const section = document.getElementById(sectionId); | |
| if (section) { | |
| section.scrollIntoView({ behavior: 'smooth', block: 'start' }); | |
| updateActiveNav(sectionId); | |
| } | |
| } | |
| function updateActiveNav(sectionId) { | |
| const navButtons = document.querySelectorAll('nav button'); | |
| navButtons.forEach(btn => { | |
| btn.classList.remove('text-primary'); | |
| btn.classList.add('text-gray-500'); | |
| }); | |
| const activeBtn = document.querySelector(`nav button[onclick*="${sectionId}"]`); | |
| if (activeBtn) { | |
| activeBtn.classList.remove('text-gray-500'); | |
| activeBtn.classList.add('text-primary'); | |
| } | |
| } | |
| // AI Analysis | |
| function runAIAnalysis() { | |
| const resultsDiv = document.getElementById('ai-results'); | |
| resultsDiv.innerHTML = '<div class="text-center py-4"><div class="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-white"></div></div>'; | |
| setTimeout(() => { | |
| const insights = [ | |
| { icon: '🧘', text: 'ควรทำสมาธิ 10 นาที ก่อนนอนเพื่อลดความเครียด' }, | |
| { icon: '💧', text: 'ต้องการดื่มน้ำเพิ่ม 500 มล. ในช่วงบ่าย' }, | |
| { icon: '🥗', text: 'แนะนำเพิ่มผักใบเขียวในมื้อเย็นวันนี้' }, | |
| { icon: '☀️', text: 'ต้องการรับแสงแดด 15 นาทีเพื่อวิตามิน D' } | |
| ]; | |
| resultsDiv.innerHTML = insights.map(insight => ` | |
| <div class="bg-white bg-opacity-20 rounded-lg p-3 slide-up"> | |
| <p class="text-sm">${insight.icon} ${insight.text}</p> | |
| </div> | |
| `).join(''); | |
| }, 1500); | |
| } | |
| // Initialize Charts | |
| function initializeCharts() { | |
| drawLineChart('hrvChart', [45, 48, 52, 50, 55, 52, 54], '#EF4444'); | |
| drawLineChart('sleepChart', [6.5, 7.2, 6.8, 7.5, 8.0, 7.8, 7.2], '#8B5CF6'); | |
| drawLineChart('weightChart', [76, 75.5, 75.8, 75.2, 75, 74.8, 75], '#3B82F6'); | |
| } | |
| function drawLineChart(canvasId, data, color) { | |
| const canvas = document.getElementById(canvasId); | |
| if (!canvas) return; | |
| const ctx = canvas.getContext('2d'); | |
| const width = canvas.width = canvas.offsetWidth; | |
| const height = canvas.height = 128; | |
| const padding = 10; | |
| const graphWidth = width - padding * 2; | |
| const graphHeight = height - padding * 2; | |
| const maxValue = Math.max(...data); | |
| const minValue = Math.min(...data); | |
| const range = maxValue - minValue; | |
| // Clear canvas | |
| ctx.clearRect(0, 0, width, height); | |
| // Draw grid lines | |
| ctx.strokeStyle = '#E5E7EB'; | |
| ctx.lineWidth = 1; | |
| for (let i = 0; i <= 4; i++) { | |
| const y = padding + (graphHeight / 4) * i; | |
| ctx.beginPath(); | |
| ctx.moveTo(padding, y); | |
| ctx.lineTo(width - padding, y); | |
| ctx.stroke(); | |
| } | |
| // Draw line chart | |
| ctx.strokeStyle = color; | |
| ctx.lineWidth = 2; | |
| ctx.beginPath(); | |
| data.forEach((value, index) => { | |
| const x = padding + (graphWidth / (data.length - 1)) * index; | |
| const y = padding + graphHeight - ((value - minValue) / range) * graphHeight; | |
| if (index === 0) { | |
| ctx.moveTo(x, y); | |
| } else { | |
| ctx.lineTo(x, y); | |
| } | |
| }); | |
| ctx.stroke(); | |
| // Draw points | |
| ctx.fillStyle = color; | |
| data.forEach((value, index) => { | |
| const x = padding + (graphWidth / (data.length - 1)) * index; | |
| const y = padding + graphHeight - ((value - minValue) / range) * graphHeight; | |
| ctx.beginPath(); | |
| ctx.arc(x, y, 3, 0, Math.PI * 2); | |
| ctx.fill(); | |
| }); | |
| } | |
| function changeTimeRange(days) { | |
| const buttons = document.querySelectorAll('.time-btn'); | |
| buttons.forEach(btn => { | |
| btn.classList.remove('bg-primary', 'text-white'); | |
| btn.classList.add('bg-gray-100', 'text-gray-600'); | |
| }); | |
| event.target.classList.remove('bg-gray-100', 'text-gray-600'); | |
| event.target.classList.add('bg-primary', 'text-white'); | |
| // Simulate loading new data | |
| const hrvData = days === '7' ? [45, 48, 52, 50, 55, 52, 54] : | |
| days === '30' ? [42, 45, 48, 46, 50, 52, 51, 53, 52, 54, 55, 53] : | |
| [40, 42, 44, 43, 45, 47, 46, 48, 49, 48, 50, 52, 51, 53, 54, 55, 54, 53, 52, 54]; | |
| drawLineChart('hrvChart', hrvData, '#EF4444'); | |
| } | |
| // Chat functions | |
| function startChat() { | |
| document.getElementById('chatModal').classList.remove('hidden'); | |
| document.body.style.overflow = 'hidden'; | |
| } | |
| function closeChat() { | |
| document.getElementById('chatModal').classList.add('hidden'); | |
| document.body.style.overflow = 'auto'; | |
| } | |
| function startVideoCall() { | |
| // Simulate video call | |
| alert('กำลังเชื่อมต่อกับ BioCoach... ฟีเจอร์วิดีโอคอลจะเปิดใช้งานเร็วๆ นี้'); | |
| } | |
| // Quick reorder | |
| function quickReorder() { | |
| // Show loading state | |
| event.target.innerHTML = '<div class="inline-block animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>'; | |
| event.target.disabled = true; | |
| setTimeout(() => { | |
| event.target.innerHTML = '✓ สั่งซื้อสำเร็จ!'; | |
| event.target.classList.remove('bg-primary'); | |
| event.target.classList.add('bg-green-500'); | |
| setTimeout(() => { | |
| event.target.innerHTML = 'สั่งซ้ำ 1 คลิก'; | |
| event.target.disabled = false; | |
| event.target.classList.remove('bg-green-500'); | |
| event.target.classList.add('bg-primary'); | |
| }, 2000); | |
| }, 1500); | |
| } | |
| // Notifications | |
| function toggleNotifications() { | |
| alert('คุณมีการแจ้งเตือนใหม่: อย่าลืมทานวิตามิน ADEK ในช่วงเช้านะครับ!'); | |
| } | |
| // Setup event listeners | |
| function setupEventListeners() { | |
| // Handle checkbox changes | |
| document.querySelectorAll('input[type="checkbox"]').forEach(checkbox => { | |
| checkbox.addEventListener('change', function() { | |
| updateProgress(); | |
| }); | |
| }); | |
| } | |
| // Update progress | |
| function updateProgress() { | |
| const checkboxes = document.querySelectorAll('#plan input[type="checkbox"]'); | |
| const checked = document.querySelectorAll('#plan input[type="checkbox"]:checked'); | |
| const percentage = Math.round((checked.length / checkboxes.length) * 100); | |
| const progressBar = document.querySelector('#plan .bg-primary.h-2'); | |
| const percentageText = document.querySelector('#plan .font-semibold'); | |
| if (progressBar) { | |
| progressBar.style.width = `${percentage}%`; | |
| } | |
| if (percentageText) { | |
| percentageText.textContent = `${percentage}%`; | |
| } | |
| } | |
| // Update real-time data | |
| function updateRealTimeData() { | |
| setInterval(() => { | |
| // Simulate real-time updates | |
| const stressElement = document.querySelector('.text-yellow-500').parentElement.parentElement.querySelector('.text-2xl'); | |
| if (stressElement && Math.random() > 0.7) { | |
| const newStress = Math.floor(Math.random() * 20) + 30; | |
| stressElement.textContent = newStress; | |
| } | |
| }, 10000); | |
| } | |
| // Handle pull-to-refresh | |
| let startY = 0; | |
| let isPulling = false; | |
| document.addEventListener('touchstart', function(e) { | |
| if (window.scrollY === 0) { | |
| startY = e.touches[0].pageY; | |
| isPulling = true; | |
| } | |
| }); | |
| document.addEventListener('touchmove', function(e) { | |
| if (!isPulling) return; | |
| const currentY = e.touches[0].pageY; | |
| const pullDistance = currentY - startY; | |
| if (pullDistance > 0 && pullDistance < 100) { | |
| e.preventDefault(); | |
| document.body.style.transform = `translateY(${pullDistance * 0.5}px)`; | |
| } | |
| }); | |
| document.addEventListener('touchend', function(e) { | |
| if (!isPulling) return; | |
| isPulling = false; | |
| document.body.style.transform = ''; | |
| const currentY = e.changedTouches[0].pageY; | |
| const pullDistance = currentY - startY; | |
| if (pullDistance > 80) { | |
| location.reload(); | |
| } | |
| }); | |
| // Lazy load images | |
| const imageObserver = new IntersectionObserver((entries, observer) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| const img = entry.target; | |
| img.src = img.dataset.src; | |
| observer.unobserve(img); | |
| } | |
| }); | |
| }); | |
| document.querySelectorAll('img[data-src]').forEach(img => { | |
| imageObserver.observe(img); | |
| }); |