diff --git a/iframe.html b/iframe.html index 0d63585..b370e17 100644 --- a/iframe.html +++ b/iframe.html @@ -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): 950→1350 + // 5–6 mo (5.0–6.0): 1250→1550; (6.0–<7.0): hold 1550 + // 7–12 mo (7.0–12.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) { diff --git a/src/js/calculator.js b/src/js/calculator.js index 40e1fe6..b6f6f31 100644 --- a/src/js/calculator.js +++ b/src/js/calculator.js @@ -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 + // 5–6 mo (5.0–6.0): 1250→1550; (6.0–<7.0): hold 1550 + // 7–12 mo (7.0–12.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) {