This commit is contained in:
Dayowe 2025-11-12 18:00:36 +01:00
parent da9fd20ffb
commit 73c4648978
2 changed files with 220 additions and 314 deletions

View File

@ -2171,11 +2171,12 @@ const CALCULATOR_CONFIG = {
// Seed three sources for Kaya's transition
const gc = {
id: this.generateFoodSourceId(),
name: 'Fred & Felia, gently cooked',
name: 'Fred & Felia (Junior Huhn)',
energy: '115',
energyUnit: 'kcal100g',
percentage: 5,
isLocked: false
isLocked: false,
chartType: 'gc'
};
this.foodSources.push(gc);
this.renderFoodSource(gc);
@ -2183,11 +2184,12 @@ const CALCULATOR_CONFIG = {
const kibble = {
id: this.generateFoodSourceId(),
name: 'Eukanuba, kibble',
name: 'Eukanuba (Large Breed Fresh Chicken)',
energy: '372',
energyUnit: 'kcal100g',
percentage: 95,
isLocked: false
isLocked: false,
chartType: 'kibble'
};
this.foodSources.push(kibble);
this.renderFoodSource(kibble);
@ -2199,7 +2201,8 @@ const CALCULATOR_CONFIG = {
energy: '',
energyUnit: 'kcal100g',
percentage: 0,
isLocked: false
isLocked: false,
chartType: null
};
this.foodSources.push(treats);
this.renderFoodSource(treats);
@ -3239,58 +3242,29 @@ const CALCULATOR_CONFIG = {
}
updateCalorieCalculations() {
// Kaya-specific: compute daily kcal target from age + kibble energy
// Kaya-specific: only track age and trigger recompute
const ageInput = document.getElementById('ageMonths');
const ageClampNote = document.getElementById('ageClampNote');
// Default: hide clamp note
if (ageClampNote) ageClampNote.classList.add('dog-calculator-hidden');
if (!ageInput || !ageInput.value) {
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
if (!ageInput || ageInput.value === '') {
this.currentAge = null;
this.updateFoodCalculations();
return;
}
let age = parseFloat(ageInput.value);
if (isNaN(age)) {
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
this.currentAge = null;
this.updateFoodCalculations();
return;
}
// Clamp age to [2, 12]
if (age < 2) { age = 2; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
if (age > 12) { age = 12; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
// Bucket pills removed
// Calculate interpolated kibble grams/day for 30 kg at this age
const kibbleGrams = this.getKayaKibbleGramsForAge(age);
// Get kibble reference energy density in kcal/100g
let kibbleEnergyPer100g = null;
if (this.kibbleRefId) {
const kibbleRef = this.foodSources.find(fs => fs.id === this.kibbleRefId);
kibbleEnergyPer100g = kibbleRef ? this.getFoodSourceEnergyPer100g(kibbleRef) : null;
}
if (!kibbleEnergyPer100g || kibbleEnergyPer100g <= 0) {
// Cannot compute without kibble energy density
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
return;
}
const kcalPerGram = kibbleEnergyPer100g / 100.0;
const dailyKcal = kibbleGrams * kcalPerGram;
this.currentMER = dailyKcal;
this.currentMERMin = dailyKcal;
this.currentMERMax = dailyKcal;
this.currentAge = age;
this.updateFoodCalculations();
}
@ -3321,38 +3295,38 @@ const CALCULATOR_CONFIG = {
return lowerVal + (upperVal - lowerVal) * t;
}
updateCupsButtonState() {
const cupsButton = document.getElementById('cupsButton');
if (!cupsButton) return;
// Check if any food source has kcal/cup selected
const hasKcalCup = this.foodSources.some(fs =>
fs.energyUnit === 'kcalcup' && fs.energy && parseFloat(fs.energy) > 0
);
if (hasKcalCup) {
cupsButton.disabled = false;
cupsButton.title = 'Show amounts in cups';
// Kaya: GC chart interpolation across buckets
getGCChartGramsForAge(ageMonths) {
// Buckets per guideline with boundary rule (5.0 → later bucket, 7.0 → later bucket)
// <5 mo (2.0<5.0): 9501350
// 56 mo (5.06.0): 1250→1550; (6.0<7.0): hold 1550
// 712 mo (7.012.0): 1300→1500
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const age = clamp(ageMonths, 2, 12);
if (age < 5) {
const t = (age - 2) / (5 - 2);
return 950 + t * (1350 - 950);
} else if (age < 6) {
const t = (age - 5) / (6 - 5);
return 1250 + t * (1550 - 1250);
} else if (age < 7) {
return 1550; // hold upper value until 7.0
} else {
cupsButton.disabled = true;
cupsButton.title = 'Available when using kcal/cup measurement';
// If cups was selected, switch back to grams
const unitSelect = document.getElementById('unit');
if (unitSelect && unitSelect.value === 'cups') {
unitSelect.value = 'g';
this.setActiveUnitButton('g');
}
const t = (age - 7) / (12 - 7);
return 1300 + t * (1500 - 1300);
}
}
updateCupsButtonState() {
// Cups UI is not used in this configuration
return;
}
updateFoodCalculations() {
if (this.currentMER === 0) return;
// Check if we have a range
const hasRange = this.currentMERMin !== this.currentMERMax;
// Chart-first: no MER check
const hasRange = false;
const daysInput = document.getElementById('days');
const unitSelect = document.getElementById('unit');
@ -3415,102 +3389,81 @@ const CALCULATOR_CONFIG = {
}
const numDays = parseInt(days);
// Calculate per-food breakdown
// Require a valid age for chart-first outputs
const ageInput = document.getElementById('ageMonths');
let age = ageInput && ageInput.value !== '' ? parseFloat(ageInput.value) : null;
if (age !== null) {
if (isNaN(age)) age = null;
if (age !== null) {
if (age < 2) age = 2;
if (age > 12) age = 12;
}
}
// Calculate per-food breakdown (chart-first)
const foodBreakdowns = [];
let totalDailyGrams = 0;
let hasValidFoods = false;
// First pass: charted baseline
let chartedKcal = 0;
let chartedPercent = 0;
const firstPass = [];
this.foodSources.forEach(fs => {
const energyPer100g = this.getFoodSourceEnergyPer100g(fs);
if (energyPer100g && energyPer100g > 0.1 && fs.percentage > 0) {
const dailyCaloriesForThisFood = (this.currentMER * fs.percentage) / 100;
// Calculate range values if applicable
const dailyCaloriesMin = hasRange ? (this.currentMERMin * fs.percentage) / 100 : dailyCaloriesForThisFood;
const dailyCaloriesMax = hasRange ? (this.currentMERMax * fs.percentage) / 100 : dailyCaloriesForThisFood;
let dailyGramsForThisFood;
let dailyGramsMin, dailyGramsMax;
let dailyCupsForThisFood = null;
let dailyCupsMin, dailyCupsMax;
// For kcal/cup, calculate cups directly from calories
if (fs.energyUnit === 'kcalcup' && fs.energy) {
const caloriesPerCup = parseFloat(fs.energy);
dailyCupsForThisFood = dailyCaloriesForThisFood / caloriesPerCup;
dailyCupsMin = dailyCaloriesMin / caloriesPerCup;
dailyCupsMax = dailyCaloriesMax / caloriesPerCup;
// We still need grams for total calculation, use approximation
dailyGramsForThisFood = (dailyCaloriesForThisFood / energyPer100g) * 100;
dailyGramsMin = (dailyCaloriesMin / energyPer100g) * 100;
dailyGramsMax = (dailyCaloriesMax / energyPer100g) * 100;
} else {
// For other units, calculate grams normally
dailyGramsForThisFood = (dailyCaloriesForThisFood / energyPer100g) * 100;
dailyGramsMin = (dailyCaloriesMin / energyPer100g) * 100;
dailyGramsMax = (dailyCaloriesMax / energyPer100g) * 100;
}
// Calculate per-meal amounts if needed
const displayGrams = this.showPerMeal ? dailyGramsForThisFood / this.mealsPerDay : dailyGramsForThisFood;
const displayGramsMin = this.showPerMeal ? dailyGramsMin / this.mealsPerDay : dailyGramsMin;
const displayGramsMax = this.showPerMeal ? dailyGramsMax / this.mealsPerDay : dailyGramsMax;
const displayCups = dailyCupsForThisFood !== null ?
(this.showPerMeal ? dailyCupsForThisFood / this.mealsPerDay : dailyCupsForThisFood) : null;
const displayCupsMin = dailyCupsMin !== undefined ?
(this.showPerMeal ? dailyCupsMin / this.mealsPerDay : dailyCupsMin) : null;
const displayCupsMax = dailyCupsMax !== undefined ?
(this.showPerMeal ? dailyCupsMax / this.mealsPerDay : dailyCupsMax) : null;
const displayCalories = this.showPerMeal ? dailyCaloriesForThisFood / this.mealsPerDay : dailyCaloriesForThisFood;
const displayCaloriesMin = this.showPerMeal ? dailyCaloriesMin / this.mealsPerDay : dailyCaloriesMin;
const displayCaloriesMax = this.showPerMeal ? dailyCaloriesMax / this.mealsPerDay : dailyCaloriesMax;
foodBreakdowns.push({
name: fs.name,
percentage: fs.percentage,
dailyGrams: dailyGramsForThisFood,
dailyGramsMin: dailyGramsMin,
dailyGramsMax: dailyGramsMax,
displayGrams: displayGrams,
displayGramsMin: displayGramsMin,
displayGramsMax: displayGramsMax,
dailyCups: dailyCupsForThisFood,
dailyCupsMin: dailyCupsMin,
dailyCupsMax: dailyCupsMax,
displayCups: displayCups,
displayCupsMin: displayCupsMin,
displayCupsMax: displayCupsMax,
calories: dailyCaloriesForThisFood,
displayCalories: displayCalories,
displayCaloriesMin: displayCaloriesMin,
displayCaloriesMax: displayCaloriesMax,
isLocked: fs.isLocked,
hasEnergyContent: true,
hasRange: hasRange,
foodSource: fs // Store reference for cups conversion
});
totalDailyGrams += dailyGramsForThisFood;
hasValidFoods = true;
} else if (fs.percentage > 0) {
// Include food sources without energy content but show them as needing energy content
foodBreakdowns.push({
name: fs.name,
percentage: fs.percentage,
dailyGrams: 0,
displayGrams: 0,
dailyCups: null,
displayCups: null,
calories: 0,
displayCalories: 0,
isLocked: fs.isLocked,
hasEnergyContent: false,
foodSource: fs // Store reference for cups conversion
});
let chartGrams = null;
if (fs.chartType === 'gc') {
chartGrams = age !== null ? this.getGCChartGramsForAge(age) : null;
} else if (fs.chartType === 'kibble') {
chartGrams = age !== null ? this.getKayaKibbleGramsForAge(age) : null;
}
const gramsPortion = (chartGrams !== null && chartGrams !== undefined) ? (chartGrams * (fs.percentage || 0) / 100) : null;
if (gramsPortion !== null && energyPer100g && energyPer100g > 0) {
chartedKcal += gramsPortion * (energyPer100g / 100);
chartedPercent += (fs.percentage || 0);
}
firstPass.push({ fs, energyPer100g, gramsPortion });
});
const kcalPerPercent = chartedPercent > 0 ? (chartedKcal / chartedPercent) : null;
// Second pass: finalize amounts
firstPass.forEach(({ fs, energyPer100g, gramsPortion }) => {
let dailyGramsForThisFood = 0;
let hasEnergyContent = !!(energyPer100g && energyPer100g > 0);
if ((fs.chartType === 'gc' || fs.chartType === 'kibble')) {
if (gramsPortion !== null) {
dailyGramsForThisFood = gramsPortion;
}
} else {
if (hasEnergyContent && kcalPerPercent && (fs.percentage || 0) > 0) {
const perGramKcal = energyPer100g / 100;
const kcalForFood = (fs.percentage || 0) * kcalPerPercent;
dailyGramsForThisFood = kcalForFood / perGramKcal;
} else {
hasEnergyContent = false;
dailyGramsForThisFood = 0;
}
}
const displayGrams = this.showPerMeal ? dailyGramsForThisFood / this.mealsPerDay : dailyGramsForThisFood;
foodBreakdowns.push({
name: fs.name,
percentage: fs.percentage,
dailyGrams: dailyGramsForThisFood,
displayGrams: displayGrams,
dailyCups: null,
displayCups: null,
calories: hasEnergyContent ? (dailyGramsForThisFood * (energyPer100g / 100)) : 0,
displayCalories: hasEnergyContent ? (this.showPerMeal ? (dailyGramsForThisFood * (energyPer100g / 100)) / this.mealsPerDay : (dailyGramsForThisFood * (energyPer100g / 100))) : 0,
isLocked: fs.isLocked,
hasEnergyContent: hasEnergyContent,
foodSource: fs
});
totalDailyGrams += dailyGramsForThisFood;
if (dailyGramsForThisFood > 0) hasValidFoods = true;
});
if (!hasValidFoods) {

View File

@ -75,11 +75,12 @@
// Seed three sources for Kaya's transition
const gc = {
id: this.generateFoodSourceId(),
name: 'Fred & Felia, gently cooked',
name: 'Fred & Felia (Junior Huhn)',
energy: '115',
energyUnit: 'kcal100g',
percentage: 5,
isLocked: false
isLocked: false,
chartType: 'gc'
};
this.foodSources.push(gc);
this.renderFoodSource(gc);
@ -87,11 +88,12 @@
const kibble = {
id: this.generateFoodSourceId(),
name: 'Eukanuba, kibble',
name: 'Eukanuba (Large Breed Fresh Chicken)',
energy: '372',
energyUnit: 'kcal100g',
percentage: 95,
isLocked: false
isLocked: false,
chartType: 'kibble'
};
this.foodSources.push(kibble);
this.renderFoodSource(kibble);
@ -103,7 +105,8 @@
energy: '',
energyUnit: 'kcal100g',
percentage: 0,
isLocked: false
isLocked: false,
chartType: null
};
this.foodSources.push(treats);
this.renderFoodSource(treats);
@ -1143,58 +1146,29 @@
}
updateCalorieCalculations() {
// Kaya-specific: compute daily kcal target from age + kibble energy
// Kaya-specific: only track age and trigger recompute
const ageInput = document.getElementById('ageMonths');
const ageClampNote = document.getElementById('ageClampNote');
// Default: hide clamp note
if (ageClampNote) ageClampNote.classList.add('dog-calculator-hidden');
if (!ageInput || !ageInput.value) {
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
if (!ageInput || ageInput.value === '') {
this.currentAge = null;
this.updateFoodCalculations();
return;
}
let age = parseFloat(ageInput.value);
if (isNaN(age)) {
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
this.currentAge = null;
this.updateFoodCalculations();
return;
}
// Clamp age to [2, 12]
if (age < 2) { age = 2; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
if (age > 12) { age = 12; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
// Bucket pills removed
// Calculate interpolated kibble grams/day for 30 kg at this age
const kibbleGrams = this.getKayaKibbleGramsForAge(age);
// Get kibble reference energy density in kcal/100g
let kibbleEnergyPer100g = null;
if (this.kibbleRefId) {
const kibbleRef = this.foodSources.find(fs => fs.id === this.kibbleRefId);
kibbleEnergyPer100g = kibbleRef ? this.getFoodSourceEnergyPer100g(kibbleRef) : null;
}
if (!kibbleEnergyPer100g || kibbleEnergyPer100g <= 0) {
// Cannot compute without kibble energy density
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
return;
}
const kcalPerGram = kibbleEnergyPer100g / 100.0;
const dailyKcal = kibbleGrams * kcalPerGram;
this.currentMER = dailyKcal;
this.currentMERMin = dailyKcal;
this.currentMERMax = dailyKcal;
this.currentAge = age;
this.updateFoodCalculations();
}
@ -1225,38 +1199,38 @@
return lowerVal + (upperVal - lowerVal) * t;
}
updateCupsButtonState() {
const cupsButton = document.getElementById('cupsButton');
if (!cupsButton) return;
// Check if any food source has kcal/cup selected
const hasKcalCup = this.foodSources.some(fs =>
fs.energyUnit === 'kcalcup' && fs.energy && parseFloat(fs.energy) > 0
);
if (hasKcalCup) {
cupsButton.disabled = false;
cupsButton.title = 'Show amounts in cups';
// Kaya: GC chart interpolation across buckets
getGCChartGramsForAge(ageMonths) {
// Buckets per guideline with boundary rule (5.0 → later bucket, 7.0 → later bucket)
// <5 mo (2.0<5.0): 950→1350
// 56 mo (5.06.0): 1250→1550; (6.0<7.0): hold 1550
// 712 mo (7.012.0): 1300→1500
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const age = clamp(ageMonths, 2, 12);
if (age < 5) {
const t = (age - 2) / (5 - 2);
return 950 + t * (1350 - 950);
} else if (age < 6) {
const t = (age - 5) / (6 - 5);
return 1250 + t * (1550 - 1250);
} else if (age < 7) {
return 1550; // hold upper value until 7.0
} else {
cupsButton.disabled = true;
cupsButton.title = 'Available when using kcal/cup measurement';
// If cups was selected, switch back to grams
const unitSelect = document.getElementById('unit');
if (unitSelect && unitSelect.value === 'cups') {
unitSelect.value = 'g';
this.setActiveUnitButton('g');
}
const t = (age - 7) / (12 - 7);
return 1300 + t * (1500 - 1300);
}
}
updateCupsButtonState() {
// Cups UI is not used in this configuration
return;
}
updateFoodCalculations() {
if (this.currentMER === 0) return;
// Check if we have a range
const hasRange = this.currentMERMin !== this.currentMERMax;
// Chart-first: no MER check
const hasRange = false;
const daysInput = document.getElementById('days');
const unitSelect = document.getElementById('unit');
@ -1319,102 +1293,81 @@
}
const numDays = parseInt(days);
// Calculate per-food breakdown
// Require a valid age for chart-first outputs
const ageInput = document.getElementById('ageMonths');
let age = ageInput && ageInput.value !== '' ? parseFloat(ageInput.value) : null;
if (age !== null) {
if (isNaN(age)) age = null;
if (age !== null) {
if (age < 2) age = 2;
if (age > 12) age = 12;
}
}
// Calculate per-food breakdown (chart-first)
const foodBreakdowns = [];
let totalDailyGrams = 0;
let hasValidFoods = false;
// First pass: charted baseline
let chartedKcal = 0;
let chartedPercent = 0;
const firstPass = [];
this.foodSources.forEach(fs => {
const energyPer100g = this.getFoodSourceEnergyPer100g(fs);
if (energyPer100g && energyPer100g > 0.1 && fs.percentage > 0) {
const dailyCaloriesForThisFood = (this.currentMER * fs.percentage) / 100;
// Calculate range values if applicable
const dailyCaloriesMin = hasRange ? (this.currentMERMin * fs.percentage) / 100 : dailyCaloriesForThisFood;
const dailyCaloriesMax = hasRange ? (this.currentMERMax * fs.percentage) / 100 : dailyCaloriesForThisFood;
let dailyGramsForThisFood;
let dailyGramsMin, dailyGramsMax;
let dailyCupsForThisFood = null;
let dailyCupsMin, dailyCupsMax;
// For kcal/cup, calculate cups directly from calories
if (fs.energyUnit === 'kcalcup' && fs.energy) {
const caloriesPerCup = parseFloat(fs.energy);
dailyCupsForThisFood = dailyCaloriesForThisFood / caloriesPerCup;
dailyCupsMin = dailyCaloriesMin / caloriesPerCup;
dailyCupsMax = dailyCaloriesMax / caloriesPerCup;
// We still need grams for total calculation, use approximation
dailyGramsForThisFood = (dailyCaloriesForThisFood / energyPer100g) * 100;
dailyGramsMin = (dailyCaloriesMin / energyPer100g) * 100;
dailyGramsMax = (dailyCaloriesMax / energyPer100g) * 100;
} else {
// For other units, calculate grams normally
dailyGramsForThisFood = (dailyCaloriesForThisFood / energyPer100g) * 100;
dailyGramsMin = (dailyCaloriesMin / energyPer100g) * 100;
dailyGramsMax = (dailyCaloriesMax / energyPer100g) * 100;
}
// Calculate per-meal amounts if needed
const displayGrams = this.showPerMeal ? dailyGramsForThisFood / this.mealsPerDay : dailyGramsForThisFood;
const displayGramsMin = this.showPerMeal ? dailyGramsMin / this.mealsPerDay : dailyGramsMin;
const displayGramsMax = this.showPerMeal ? dailyGramsMax / this.mealsPerDay : dailyGramsMax;
const displayCups = dailyCupsForThisFood !== null ?
(this.showPerMeal ? dailyCupsForThisFood / this.mealsPerDay : dailyCupsForThisFood) : null;
const displayCupsMin = dailyCupsMin !== undefined ?
(this.showPerMeal ? dailyCupsMin / this.mealsPerDay : dailyCupsMin) : null;
const displayCupsMax = dailyCupsMax !== undefined ?
(this.showPerMeal ? dailyCupsMax / this.mealsPerDay : dailyCupsMax) : null;
const displayCalories = this.showPerMeal ? dailyCaloriesForThisFood / this.mealsPerDay : dailyCaloriesForThisFood;
const displayCaloriesMin = this.showPerMeal ? dailyCaloriesMin / this.mealsPerDay : dailyCaloriesMin;
const displayCaloriesMax = this.showPerMeal ? dailyCaloriesMax / this.mealsPerDay : dailyCaloriesMax;
foodBreakdowns.push({
name: fs.name,
percentage: fs.percentage,
dailyGrams: dailyGramsForThisFood,
dailyGramsMin: dailyGramsMin,
dailyGramsMax: dailyGramsMax,
displayGrams: displayGrams,
displayGramsMin: displayGramsMin,
displayGramsMax: displayGramsMax,
dailyCups: dailyCupsForThisFood,
dailyCupsMin: dailyCupsMin,
dailyCupsMax: dailyCupsMax,
displayCups: displayCups,
displayCupsMin: displayCupsMin,
displayCupsMax: displayCupsMax,
calories: dailyCaloriesForThisFood,
displayCalories: displayCalories,
displayCaloriesMin: displayCaloriesMin,
displayCaloriesMax: displayCaloriesMax,
isLocked: fs.isLocked,
hasEnergyContent: true,
hasRange: hasRange,
foodSource: fs // Store reference for cups conversion
});
totalDailyGrams += dailyGramsForThisFood;
hasValidFoods = true;
} else if (fs.percentage > 0) {
// Include food sources without energy content but show them as needing energy content
foodBreakdowns.push({
name: fs.name,
percentage: fs.percentage,
dailyGrams: 0,
displayGrams: 0,
dailyCups: null,
displayCups: null,
calories: 0,
displayCalories: 0,
isLocked: fs.isLocked,
hasEnergyContent: false,
foodSource: fs // Store reference for cups conversion
});
let chartGrams = null;
if (fs.chartType === 'gc') {
chartGrams = age !== null ? this.getGCChartGramsForAge(age) : null;
} else if (fs.chartType === 'kibble') {
chartGrams = age !== null ? this.getKayaKibbleGramsForAge(age) : null;
}
const gramsPortion = (chartGrams !== null && chartGrams !== undefined) ? (chartGrams * (fs.percentage || 0) / 100) : null;
if (gramsPortion !== null && energyPer100g && energyPer100g > 0) {
chartedKcal += gramsPortion * (energyPer100g / 100);
chartedPercent += (fs.percentage || 0);
}
firstPass.push({ fs, energyPer100g, gramsPortion });
});
const kcalPerPercent = chartedPercent > 0 ? (chartedKcal / chartedPercent) : null;
// Second pass: finalize amounts
firstPass.forEach(({ fs, energyPer100g, gramsPortion }) => {
let dailyGramsForThisFood = 0;
let hasEnergyContent = !!(energyPer100g && energyPer100g > 0);
if ((fs.chartType === 'gc' || fs.chartType === 'kibble')) {
if (gramsPortion !== null) {
dailyGramsForThisFood = gramsPortion;
}
} else {
if (hasEnergyContent && kcalPerPercent && (fs.percentage || 0) > 0) {
const perGramKcal = energyPer100g / 100;
const kcalForFood = (fs.percentage || 0) * kcalPerPercent;
dailyGramsForThisFood = kcalForFood / perGramKcal;
} else {
hasEnergyContent = false;
dailyGramsForThisFood = 0;
}
}
const displayGrams = this.showPerMeal ? dailyGramsForThisFood / this.mealsPerDay : dailyGramsForThisFood;
foodBreakdowns.push({
name: fs.name,
percentage: fs.percentage,
dailyGrams: dailyGramsForThisFood,
displayGrams: displayGrams,
dailyCups: null,
displayCups: null,
calories: hasEnergyContent ? (dailyGramsForThisFood * (energyPer100g / 100)) : 0,
displayCalories: hasEnergyContent ? (this.showPerMeal ? (dailyGramsForThisFood * (energyPer100g / 100)) / this.mealsPerDay : (dailyGramsForThisFood * (energyPer100g / 100))) : 0,
isLocked: fs.isLocked,
hasEnergyContent: hasEnergyContent,
foodSource: fs
});
totalDailyGrams += dailyGramsForThisFood;
if (dailyGramsForThisFood > 0) hasValidFoods = true;
});
if (!hasValidFoods) {