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.");
}
});