let profile = null; let entries = []; document.addEventListener('DOMContentLoaded', () => { document.getElementById('entryDate').valueAsDate = new Date(); document.getElementById('filterDate').valueAsDate = new Date(); loadProfile(); loadEntries(); }); document.getElementById('profileForm').addEventListener('submit', async (e) => { e.preventDefault(); const gender = document.getElementById('gender').value; const age = parseInt(document.getElementById('age').value); const height = parseInt(document.getElementById('height').value); const weight = parseInt(document.getElementById('weight').value); const activity = parseFloat(document.getElementById('activity').value); const goal = document.getElementById('goal').value; let bmr; if (gender === 'male') { bmr = 88.362 + (13.397 * weight) + (4.799 * height) - (5.677 * age); } else { bmr = 447.593 + (9.247 * weight) + (3.098 * height) - (4.330 * age); } const tdee = Math.round(bmr * activity); let goalCalories; if (goal === 'lose') { goalCalories = Math.round(tdee * 0.8); } else if (goal === 'gain') { goalCalories = Math.round(tdee * 1.15); } else { goalCalories = tdee; } profile = { gender, age, height, weight, activity, goal, bmr: Math.round(bmr), tdee, goalCalories }; await fetch('/api/profile', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(profile) }); document.getElementById('bmrValue').textContent = Math.round(bmr) + ' ккал'; document.getElementById('tdeeValue').textContent = tdee + ' ккал'; document.getElementById('goalValue').textContent = goalCalories + ' ккал'; document.getElementById('result').style.display = 'block'; document.getElementById('goalCalories').textContent = goalCalories + ' ккал'; updateStats(); }); document.getElementById('entryForm').addEventListener('submit', async (e) => { e.preventDefault(); const entry = { foodName: document.getElementById('foodName').value, calories: parseInt(document.getElementById('calories').value), protein: parseFloat(document.getElementById('protein').value) || 0, fat: parseFloat(document.getElementById('fat').value) || 0, carbs: parseFloat(document.getElementById('carbs').value) || 0, date: document.getElementById('entryDate').value }; await fetch('/api/entries', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(entry) }); document.getElementById('foodName').value = ''; document.getElementById('calories').value = ''; document.getElementById('protein').value = ''; document.getElementById('fat').value = ''; document.getElementById('carbs').value = ''; loadEntries(); }); async function loadProfile() { const res = await fetch('/api/profile'); profile = await res.json(); if (profile) { document.getElementById('gender').value = profile.gender; document.getElementById('age').value = profile.age; document.getElementById('height').value = profile.height; document.getElementById('weight').value = profile.weight; document.getElementById('activity').value = profile.activity; document.getElementById('goal').value = profile.goal; document.getElementById('goalCalories').textContent = profile.goalCalories + ' ккал'; updateStats(); } } async function loadEntries() { const res = await fetch('/api/entries'); entries = await res.json(); renderEntries(entries); updateStats(); } function renderEntries(entriesToRender) { const container = document.getElementById('entriesList'); if (entriesToRender.length === 0) { container.innerHTML = '
Пока нет записей. Добавь первую!
'; return; } const sorted = [...entriesToRender].sort((a, b) => new Date(b.date) - new Date(a.date)); container.innerHTML = sorted.map(entry => `
${escapeHtml(entry.foodName)}
${formatDate(entry.date)}
Б: ${entry.protein}г | Ж: ${entry.fat}г | У: ${entry.carbs}г
${entry.calories} ккал ${formatDate(entry.date)}
`).join(''); } function deleteEntry(id) { if (confirm('Удалить эту запись?')) { fetch('/api/entries', { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id }) }).then(loadEntries); } } function filterByDate() { const date = document.getElementById('filterDate').value; const filtered = entries.filter(e => e.date === date); renderEntries(filtered); } function clearFilter() { renderEntries(entries); } function updateStats() { if (!profile) return; const today = new Date().toISOString().split('T')[0]; const todayEntries = entries.filter(e => e.date === today); const todayCalories = todayEntries.reduce((sum, e) => sum + e.calories, 0); document.getElementById('todayCalories').textContent = todayCalories + ' ккал'; document.getElementById('goalCalories').textContent = profile.goalCalories + ' ккал'; const remaining = profile.goalCalories - todayCalories; const remainingEl = document.getElementById('remainingCalories'); remainingEl.textContent = remaining + ' ккал'; remainingEl.style.color = remaining >= 0 ? '#10b981' : '#ef4444'; } function exportCsv() { if (entries.length === 0) { alert('Нет записей для экспорта'); return; } const head = ['Дата', 'Продукт', 'Ккал', 'Белки (г)', 'Жиры (г)', 'Углеводы (г)']; const body = entries.map(e => [ e.date, '"' + e.foodName.replace(/"/g, '""') + '"', e.calories, e.protein, e.fat, e.carbs ].join(';')); const csv = '\uFEFF' + [head.join(';'), ...body].join('\n'); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'dnevnik_pitaniya.csv'; a.click(); URL.revokeObjectURL(url); } function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function formatDate(dateStr) { const [year, month, day] = dateStr.split('-'); return `${day}.${month}.${year}`; }