Nutrition Tracking Dashboard

Nutrition Tracking Dashboard

Log meals and analyze your daily nutritional intake.

Today's Summary

Macronutrient Breakdown

Calorie Intake by Meal

Today's Food Log

Meal Food Calories Protein (g) Carbs (g) Fat (g)

Log Your Meals

No entries for this date.

`; kpiTitle.textContent = `Summary for ${new Date(state.selectedDate + 'T00:00:00').toLocaleDateString()}`; return; } const totalCalories = dailyData.reduce((sum, e) => sum + e.calories, 0); const totalProtein = dailyData.reduce((sum, e) => sum + e.protein, 0); const totalCarbs = dailyData.reduce((sum, e) => sum + e.carbs, 0); const totalFat = dailyData.reduce((sum, e) => sum + e.fat, 0); kpiTitle.textContent = `Summary for ${new Date(state.selectedDate + 'T00:00:00').toLocaleDateString()}`; kpiCardsContainer.innerHTML = `

Total Calories

${totalCalories.toLocaleString()}

Protein (g)

${totalProtein.toLocaleString()}

Carbs (g)

${totalCarbs.toLocaleString()}

Fat (g)

${totalFat.toLocaleString()}

`; }; const renderDataTable = (dailyData) => { dataTableBody.innerHTML = ''; dailyData.forEach(e => { const row = ` ${e.meal} ${e.food} ${e.calories} ${e.protein} ${e.carbs} ${e.fat} `; dataTableBody.innerHTML += row; }); }; const renderCharts = (dailyData) => { // Macro Chart (Doughnut) const totalProtein = dailyData.reduce((sum, e) => sum + e.protein, 0); const totalCarbs = dailyData.reduce((sum, e) => sum + e.carbs, 0); const totalFat = dailyData.reduce((sum, e) => sum + e.fat, 0); if (macroChart) macroChart.destroy(); macroChart = new Chart(macroCanvas.getContext('2d'), { type: 'doughnut', data: { labels: ['Protein (g)', 'Carbs (g)', 'Fat (g)'], datasets: [{ data: [totalProtein, totalCarbs, totalFat], backgroundColor: ['#16a34a', '#f59e0b', '#ef4444'], }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top' } } } }); // Calorie by Meal Chart (Bar) const caloriesByMeal = dailyData.reduce((acc, e) => { acc[e.meal] = (acc[e.meal] || 0) + e.calories; return acc; }, {}); const mealLabels = Object.keys(caloriesByMeal); const mealData = mealLabels.map(label => caloriesByMeal[label]); if (calorieChart) calorieChart.destroy(); calorieChart = new Chart(calorieCanvas.getContext('2d'), { type: 'bar', data: { labels: mealLabels, datasets: [{ label: 'Calories', data: mealData, backgroundColor: 'rgba(59, 130, 246, 0.7)', }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } } } }); }; const renderConfigRows = () => { configRowsContainer.innerHTML = ''; const sortedEntries = [...state.entries].sort((a, b) => new Date(b.date) - new Date(a.date)); sortedEntries.forEach(e => { const row = `
`; configRowsContainer.innerHTML += row; }); addConfigEventListeners(); }; // --- EVENT HANDLERS --- const handleConfigChange = (e) => { const id = parseInt(e.target.dataset.id); const field = e.target.dataset.field; const value = (e.target.type === 'number') ? parseInt(e.target.value, 10) || 0 : e.target.value; const entry = state.entries.find(en => en.id === id); if (entry) entry[field] = value; renderAll(); }; const handleAddEntry = () => { const newId = state.entries.length > 0 ? Math.max(...state.entries.map(e => e.id)) + 1 : 1; state.entries.push({ id: newId, date: state.selectedDate, meal: "Snack", food: "New Food", calories: 0, protein: 0, carbs: 0, fat: 0 }); renderAll(); }; const handleRemoveEntry = (e) => { const id = parseInt(e.currentTarget.dataset.id); state.entries = state.entries.filter(en => en.id !== id); renderAll(); }; const handleDateFilterChange = (e) => { state.selectedDate = e.target.value; renderAll(); }; const addConfigEventListeners = () => { document.querySelectorAll('.config-input').forEach(input => input.addEventListener('change', handleConfigChange)); document.querySelectorAll('.remove-entry-btn').forEach(button => button.addEventListener('click', handleRemoveEntry)); }; const handleDownloadPdf = () => { const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-content'); document.querySelectorAll('.no-print').forEach(el => el.style.display = 'none'); Chart.defaults.animation = false; html2canvas(pdfContent, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(canvas => { document.querySelectorAll('.no-print').forEach(el => el.style.display = 'block'); Chart.defaults.animation = true; const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const imgWidth = pdfWidth - 20; const imgHeight = canvas.height * imgWidth / canvas.width; pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight); pdf.save(`Nutrition-Summary-${state.selectedDate}.pdf`); }); }; // --- TABBING LOGIC --- let currentTabIndex = 0; const updateTabButtons = () => { prevTabBtn.disabled = currentTabIndex === 0; nextTabBtn.disabled = currentTabIndex === tabContents.length - 1; }; const switchTab = (index) => { tabButtons.forEach(btn => btn.classList.remove('active')); tabContents.forEach(content => content.classList.remove('active')); tabButtons[index].classList.add('active'); tabContents[index].classList.add('active'); currentTabIndex = index; updateTabButtons(); }; tabButtons.forEach((button, index) => button.addEventListener('click', () => switchTab(index))); prevTabBtn.addEventListener('click', () => { if (currentTabIndex > 0) switchTab(currentTabIndex - 1); }); nextTabBtn.addEventListener('click', () => { if (currentTabIndex < tabContents.length - 1) switchTab(currentTabIndex + 1); }); // --- INITIALIZATION --- if (kpiCardsContainer && addEntryBtn && downloadPdfBtn && dateFilter) { dateFilter.value = state.selectedDate; addEntryBtn.addEventListener('click', handleAddEntry); downloadPdfBtn.addEventListener('click', handleDownloadPdf); dateFilter.addEventListener('change', handleDateFilterChange); renderAll(); updateTabButtons(); } else { console.error("Essential dashboard elements could not be found."); } });
Scroll to Top