export function calorieNeedsCalculator(form: FormTs) {
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Calorie Needs Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Personal Info Section
const personalSection = form.addSubform('personal', { title: '👤 Personal Information' });
personalSection.addRow(row => {
row.addInteger('age', {
label: 'Age',
min: 15,
max: 100,
defaultValue: 30,
suffix: 'years',
isRequired: true
}, '1fr');
row.addRadioButton('gender', {
label: 'Gender',
options: [
{ id: 'male', name: 'Male' },
{ id: 'female', name: 'Female' }
],
defaultValue: 'male',
isRequired: true
}, '1fr');
});
// Measurements Section
const measurementsSection = form.addSubform('measurements', { title: '📏 Body Measurements' });
measurementsSection.addRow(row => {
row.addRadioButton('units', {
label: 'Unit System',
options: [
{ id: 'imperial', name: 'Imperial (lbs, ft/in)' },
{ id: 'metric', name: 'Metric (kg, cm)' }
],
defaultValue: 'metric',
isRequired: true
});
});
// Imperial inputs
measurementsSection.addRow(row => {
row.addDecimal('weightLbs', {
label: 'Weight',
min: 66,
max: 700,
defaultValue: 176,
suffix: 'lbs',
isRequired: true,
isVisible: () => measurementsSection.radioButton('units')?.value() === 'imperial'
}, '1fr');
row.addInteger('heightFeet', {
label: 'Height (feet)',
min: 4,
max: 7,
defaultValue: 5,
suffix: 'ft',
isRequired: true,
isVisible: () => measurementsSection.radioButton('units')?.value() === 'imperial'
}, '1fr');
row.addInteger('heightInches', {
label: 'Height (inches)',
min: 0,
max: 11,
defaultValue: 10,
suffix: 'in',
isRequired: true,
isVisible: () => measurementsSection.radioButton('units')?.value() === 'imperial'
}, '1fr');
});
// Metric inputs
measurementsSection.addRow(row => {
row.addDecimal('weightKg', {
label: 'Weight',
min: 30,
max: 320,
defaultValue: 80,
suffix: 'kg',
isRequired: true,
isVisible: () => measurementsSection.radioButton('units')?.value() === 'metric'
}, '1fr');
row.addInteger('heightCm', {
label: 'Height',
min: 120,
max: 230,
defaultValue: 178,
suffix: 'cm',
isRequired: true,
isVisible: () => measurementsSection.radioButton('units')?.value() === 'metric'
}, '1fr');
});
// Activity Level Section
const activitySection = form.addSubform('activity', { title: '🏃 Activity Level' });
activitySection.addRow(row => {
row.addDropdown('activityLevel', {
label: 'Daily Activity Level',
options: [
{ id: 'sedentary', name: 'Sedentary (desk job, little exercise)' },
{ id: 'light', name: 'Lightly Active (light exercise 1-3 days/week)' },
{ id: 'moderate', name: 'Moderately Active (exercise 3-5 days/week)' },
{ id: 'active', name: 'Very Active (hard exercise 6-7 days/week)' },
{ id: 'extreme', name: 'Extremely Active (athlete/physical job)' }
],
defaultValue: 'moderate',
isRequired: true
});
});
activitySection.addRow(row => {
row.addTextPanel('activityDescription', {
computedValue: () => {
const activity = activitySection.dropdown('activityLevel')?.value() || 'moderate';
const descriptions: Record<string, string> = {
'sedentary': 'Multiplier: 1.2 - Office work with no exercise routine',
'light': 'Multiplier: 1.375 - Walking, light cardio, or casual sports',
'moderate': 'Multiplier: 1.55 - Regular gym sessions or sports 3-5x/week',
'active': 'Multiplier: 1.725 - Intense training nearly every day',
'extreme': 'Multiplier: 1.9 - Professional athlete or very physical labor'
};
return descriptions[activity] || '';
},
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'text-align': 'center' }
});
});
// Goal Section
const goalSection = form.addSubform('goal', { title: '🎯 Your Goal' });
goalSection.addRow(row => {
row.addRadioButton('fitnessGoal', {
label: 'What is your goal?',
options: [
{ id: 'lose', name: 'Lose Weight' },
{ id: 'maintain', name: 'Maintain Weight' },
{ id: 'gain', name: 'Build Muscle' }
],
defaultValue: 'maintain',
isRequired: true
});
});
goalSection.addRow(row => {
row.addDropdown('deficitSurplus', {
label: 'Rate of Change',
options: [
{ id: 'slow', name: 'Slow (250 cal/day)' },
{ id: 'moderate', name: 'Moderate (500 cal/day)' },
{ id: 'aggressive', name: 'Aggressive (750 cal/day)' }
],
defaultValue: 'moderate',
isVisible: () => goalSection.radioButton('fitnessGoal')?.value() !== 'maintain',
tooltip: 'How aggressively you want to change weight'
});
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Results Section
const resultsSection = form.addSubform('results', { title: '🔥 Your Calorie Needs', isCollapsible: false });
resultsSection.addRow(row => {
row.addPriceDisplay('bmr', {
label: 'Basal Metabolic Rate (BMR)',
computedValue: () => {
const units = measurementsSection.radioButton('units')?.value() || 'metric';
const gender = personalSection.radioButton('gender')?.value() || 'male';
const age = personalSection.integer('age')?.value() || 30;
let weightKg: number;
let heightCm: number;
if (units === 'imperial') {
weightKg = (measurementsSection.decimal('weightLbs')?.value() || 176) * 0.453592;
const feet = measurementsSection.integer('heightFeet')?.value() || 5;
const inches = measurementsSection.integer('heightInches')?.value() || 10;
heightCm = ((feet * 12) + inches) * 2.54;
} else {
weightKg = measurementsSection.decimal('weightKg')?.value() || 80;
heightCm = measurementsSection.integer('heightCm')?.value() || 178;
}
// Mifflin-St Jeor Equation
let bmr: number;
if (gender === 'male') {
bmr = (10 * weightKg) + (6.25 * heightCm) - (5 * age) + 5;
} else {
bmr = (10 * weightKg) + (6.25 * heightCm) - (5 * age) - 161;
}
return Math.round(bmr);
},
variant: 'default',
prefix: '',
suffix: ' cal',
tooltip: 'Calories burned at complete rest'
}, '1fr');
row.addPriceDisplay('tdee', {
label: 'Daily Energy Expenditure (TDEE)',
computedValue: () => {
const units = measurementsSection.radioButton('units')?.value() || 'metric';
const gender = personalSection.radioButton('gender')?.value() || 'male';
const age = personalSection.integer('age')?.value() || 30;
const activity = activitySection.dropdown('activityLevel')?.value() || 'moderate';
let weightKg: number;
let heightCm: number;
if (units === 'imperial') {
weightKg = (measurementsSection.decimal('weightLbs')?.value() || 176) * 0.453592;
const feet = measurementsSection.integer('heightFeet')?.value() || 5;
const inches = measurementsSection.integer('heightInches')?.value() || 10;
heightCm = ((feet * 12) + inches) * 2.54;
} else {
weightKg = measurementsSection.decimal('weightKg')?.value() || 80;
heightCm = measurementsSection.integer('heightCm')?.value() || 178;
}
let bmr: number;
if (gender === 'male') {
bmr = (10 * weightKg) + (6.25 * heightCm) - (5 * age) + 5;
} else {
bmr = (10 * weightKg) + (6.25 * heightCm) - (5 * age) - 161;
}
const multipliers: Record<string, number> = {
'sedentary': 1.2,
'light': 1.375,
'moderate': 1.55,
'active': 1.725,
'extreme': 1.9
};
return Math.round(bmr * (multipliers[activity] || 1.55));
},
variant: 'success',
prefix: '',
suffix: ' cal',
tooltip: 'Total calories burned per day'
}, '1fr');
});
// Target Calories Section
const targetSection = form.addSubform('target', { title: '🎯 Target Calories', isCollapsible: false });
targetSection.addRow(row => {
row.addPriceDisplay('targetCalories', {
label: 'Daily Calorie Target',
computedValue: () => {
const units = measurementsSection.radioButton('units')?.value() || 'metric';
const gender = personalSection.radioButton('gender')?.value() || 'male';
const age = personalSection.integer('age')?.value() || 30;
const activity = activitySection.dropdown('activityLevel')?.value() || 'moderate';
const goal = goalSection.radioButton('fitnessGoal')?.value() || 'maintain';
const rate = goalSection.dropdown('deficitSurplus')?.value() || 'moderate';
let weightKg: number;
let heightCm: number;
if (units === 'imperial') {
weightKg = (measurementsSection.decimal('weightLbs')?.value() || 176) * 0.453592;
const feet = measurementsSection.integer('heightFeet')?.value() || 5;
const inches = measurementsSection.integer('heightInches')?.value() || 10;
heightCm = ((feet * 12) + inches) * 2.54;
} else {
weightKg = measurementsSection.decimal('weightKg')?.value() || 80;
heightCm = measurementsSection.integer('heightCm')?.value() || 178;
}
let bmr: number;
if (gender === 'male') {
bmr = (10 * weightKg) + (6.25 * heightCm) - (5 * age) + 5;
} else {
bmr = (10 * weightKg) + (6.25 * heightCm) - (5 * age) - 161;
}
const multipliers: Record<string, number> = {
'sedentary': 1.2,
'light': 1.375,
'moderate': 1.55,
'active': 1.725,
'extreme': 1.9
};
const tdee = bmr * (multipliers[activity] || 1.55);
const adjustments: Record<string, number> = {
'slow': 250,
'moderate': 500,
'aggressive': 750
};
const adjustment = adjustments[rate] || 500;
if (goal === 'lose') {
return Math.round(Math.max(tdee - adjustment, 1200));
} else if (goal === 'gain') {
return Math.round(tdee + adjustment);
}
return Math.round(tdee);
},
variant: 'large',
prefix: '',
suffix: ' cal/day'
});
});
targetSection.addRow(row => {
row.addTextPanel('goalExplanation', {
computedValue: () => {
const goal = goalSection.radioButton('fitnessGoal')?.value() || 'maintain';
const rate = goalSection.dropdown('deficitSurplus')?.value() || 'moderate';
const adjustments: Record<string, number> = {
'slow': 250,
'moderate': 500,
'aggressive': 750
};
const adjustment = adjustments[rate] || 500;
const weeklyChange = (Number(adjustment * 7 / 7700) || 0).toFixed(2); // ~7700 cal = 1kg
if (goal === 'lose') {
return `Deficit of ${adjustment} cal/day = ~${weeklyChange} kg (${(Number(parseFloat(weeklyChange) * 2.2) || 0).toFixed(1)} lbs) loss per week`;
} else if (goal === 'gain') {
return `Surplus of ${adjustment} cal/day = ~${weeklyChange} kg (${(Number(parseFloat(weeklyChange) * 2.2) || 0).toFixed(1)} lbs) gain per week`;
}
return 'Eating at maintenance will keep your current weight stable';
},
customStyles: { 'font-size': '0.9rem', 'color': '#475569', 'text-align': 'center', 'font-weight': '500' }
});
});
// Macros Section
const macrosSection = form.addSubform('macros', { title: '🥗 Macro Recommendations', isCollapsible: false });
macrosSection.addRow(row => {
row.addPriceDisplay('protein', {
label: 'Protein',
computedValue: () => {
const units = measurementsSection.radioButton('units')?.value() || 'metric';
const goal = goalSection.radioButton('fitnessGoal')?.value() || 'maintain';
let weightKg: number;
if (units === 'imperial') {
weightKg = (measurementsSection.decimal('weightLbs')?.value() || 176) * 0.453592;
} else {
weightKg = measurementsSection.decimal('weightKg')?.value() || 80;
}
// 1.6-2.2g per kg for muscle building, 1.2-1.6g for maintenance
const proteinPerKg = goal === 'gain' ? 2.0 : (goal === 'lose' ? 1.8 : 1.4);
return Math.round(weightKg * proteinPerKg);
},
variant: 'default',
prefix: '',
suffix: 'g',
tooltip: 'Essential for muscle repair and growth'
}, '1fr');
row.addPriceDisplay('carbs', {
label: 'Carbohydrates',
computedValue: () => {
const units = measurementsSection.radioButton('units')?.value() || 'metric';
const gender = personalSection.radioButton('gender')?.value() || 'male';
const age = personalSection.integer('age')?.value() || 30;
const activity = activitySection.dropdown('activityLevel')?.value() || 'moderate';
const goal = goalSection.radioButton('fitnessGoal')?.value() || 'maintain';
const rate = goalSection.dropdown('deficitSurplus')?.value() || 'moderate';
let weightKg: number;
let heightCm: number;
if (units === 'imperial') {
weightKg = (measurementsSection.decimal('weightLbs')?.value() || 176) * 0.453592;
const feet = measurementsSection.integer('heightFeet')?.value() || 5;
const inches = measurementsSection.integer('heightInches')?.value() || 10;
heightCm = ((feet * 12) + inches) * 2.54;
} else {
weightKg = measurementsSection.decimal('weightKg')?.value() || 80;
heightCm = measurementsSection.integer('heightCm')?.value() || 178;
}
let bmr: number;
if (gender === 'male') {
bmr = (10 * weightKg) + (6.25 * heightCm) - (5 * age) + 5;
} else {
bmr = (10 * weightKg) + (6.25 * heightCm) - (5 * age) - 161;
}
const multipliers: Record<string, number> = {
'sedentary': 1.2,
'light': 1.375,
'moderate': 1.55,
'active': 1.725,
'extreme': 1.9
};
let tdee = bmr * (multipliers[activity] || 1.55);
const adjustments: Record<string, number> = {
'slow': 250,
'moderate': 500,
'aggressive': 750
};
const adjustment = adjustments[rate] || 500;
if (goal === 'lose') {
tdee = Math.max(tdee - adjustment, 1200);
} else if (goal === 'gain') {
tdee = tdee + adjustment;
}
const proteinPerKg = goal === 'gain' ? 2.0 : (goal === 'lose' ? 1.8 : 1.4);
const protein = weightKg * proteinPerKg;
const fat = weightKg * (goal === 'lose' ? 0.8 : 1.0);
const proteinCals = protein * 4;
const fatCals = fat * 9;
const carbCals = tdee - proteinCals - fatCals;
return Math.round(Math.max(carbCals / 4, 50));
},
variant: 'default',
prefix: '',
suffix: 'g',
tooltip: 'Primary energy source'
}, '1fr');
row.addPriceDisplay('fat', {
label: 'Fat',
computedValue: () => {
const units = measurementsSection.radioButton('units')?.value() || 'metric';
const goal = goalSection.radioButton('fitnessGoal')?.value() || 'maintain';
let weightKg: number;
if (units === 'imperial') {
weightKg = (measurementsSection.decimal('weightLbs')?.value() || 176) * 0.453592;
} else {
weightKg = measurementsSection.decimal('weightKg')?.value() || 80;
}
// 0.8-1.0g per kg
const fatPerKg = goal === 'lose' ? 0.8 : 1.0;
return Math.round(weightKg * fatPerKg);
},
variant: 'default',
prefix: '',
suffix: 'g',
tooltip: 'Essential for hormones and nutrient absorption'
}, '1fr');
});
macrosSection.addRow(row => {
row.addTextPanel('macroNote', {
computedValue: () => 'Protein: 4 cal/g | Carbs: 4 cal/g | Fat: 9 cal/g',
customStyles: { 'font-size': '0.8rem', 'color': '#64748b', 'text-align': 'center' }
});
});
// Summary Section
const summarySection = form.addSubform('summary', {
title: '📋 Summary',
isCollapsible: false,
sticky: 'bottom'
});
summarySection.addRow(row => {
row.addTextPanel('summaryText', {
computedValue: () => {
const goal = goalSection.radioButton('fitnessGoal')?.value() || 'maintain';
const goalLabels: Record<string, string> = {
'lose': 'Weight Loss',
'maintain': 'Maintenance',
'gain': 'Muscle Building'
};
return `Goal: ${goalLabels[goal] || 'Maintenance'}`;
},
customStyles: { 'font-size': '1rem', 'font-weight': '600', 'text-align': 'center', 'color': '#1e293b' }
});
});
summarySection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'These are estimates. Individual needs vary. Consult a healthcare provider or registered dietitian for personalized advice.',
customStyles: { 'font-size': '0.8rem', 'color': '#64748b', 'text-align': 'center' }
});
});
form.configureSubmitButton({
label: 'Save My Plan'
});
}