kalkulyator-kaloriy/script.js

200 lines
6.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 = '<div class="empty-state">Пока нет записей. Добавь первую!</div>';
return;
}
const sorted = [...entriesToRender].sort((a, b) => new Date(b.date) - new Date(a.date));
container.innerHTML = sorted.map(entry => `
<div class="entry-item">
<div class="entry-info">
<div class="entry-name">${escapeHtml(entry.foodName)}</div>
<div class="entry-details">${formatDate(entry.date)}</div>
<div class="entry-macros">Б: ${entry.protein}г | Ж: ${entry.fat}г | У: ${entry.carbs}г</div>
</div>
<span class="entry-calories">${entry.calories} ккал</span>
<span class="entry-date">${formatDate(entry.date)}</span>
<button onclick="deleteEntry(${entry.id})" class="btn btn-danger">Удалить</button>
</div>
`).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}`;
}