Skip to content

Commit 616ef56

Browse files
author
CP-Tiwari
committed
feat(plays): add BMR and TDEE calculator play
Add a new play that calculates Basal Metabolic Rate and Total Daily Energy Expenditure using the Mifflin-St Jeor Equation. Features include metric and imperial unit support, five activity levels, weight loss and gain calorie targets, responsive design, and smooth result animations. Closes #1660
1 parent b905e13 commit 616ef56

5 files changed

Lines changed: 733 additions & 0 deletions

File tree

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
import PlayHeader from 'common/playlists/PlayHeader';
2+
import { useState } from 'react';
3+
import './styles.css';
4+
5+
// WARNING: Do not change the entry component name
6+
function BmrTdeeCalculator(props) {
7+
const [gender, setGender] = useState('male');
8+
const [age, setAge] = useState('');
9+
const [weight, setWeight] = useState('');
10+
const [height, setHeight] = useState('');
11+
const [activityLevel, setActivityLevel] = useState('1.2');
12+
const [unit, setUnit] = useState('metric');
13+
const [result, setResult] = useState(null);
14+
15+
const activityOptions = [
16+
{ value: '1.2', label: 'Sedentary', desc: 'Little or no exercise' },
17+
{ value: '1.375', label: 'Lightly Active', desc: 'Exercise 1-3 days/week' },
18+
{ value: '1.55', label: 'Moderately Active', desc: 'Exercise 3-5 days/week' },
19+
{ value: '1.725', label: 'Very Active', desc: 'Exercise 6-7 days/week' },
20+
{ value: '1.9', label: 'Extra Active', desc: 'Very hard exercise or physical job' }
21+
];
22+
23+
const calculateBMR = () => {
24+
const ageNum = parseFloat(age);
25+
let weightKg = parseFloat(weight);
26+
let heightCm = parseFloat(height);
27+
28+
if (!ageNum || !weightKg || !heightCm) {
29+
return;
30+
}
31+
32+
// Convert imperial to metric if needed
33+
if (unit === 'imperial') {
34+
weightKg = weightKg * 0.453592; // lbs to kg
35+
heightCm = heightCm * 2.54; // inches to cm
36+
}
37+
38+
// Mifflin-St Jeor Equation
39+
let bmr;
40+
if (gender === 'male') {
41+
bmr = 10 * weightKg + 6.25 * heightCm - 5 * ageNum + 5;
42+
} else {
43+
bmr = 10 * weightKg + 6.25 * heightCm - 5 * ageNum - 161;
44+
}
45+
46+
const activity = parseFloat(activityLevel);
47+
const tdee = bmr * activity;
48+
49+
setResult({
50+
bmr: Math.round(bmr),
51+
tdee: Math.round(tdee),
52+
deficit: Math.round(tdee - 500),
53+
surplus: Math.round(tdee + 500)
54+
});
55+
};
56+
57+
const handleReset = () => {
58+
setGender('male');
59+
setAge('');
60+
setWeight('');
61+
setHeight('');
62+
setActivityLevel('1.2');
63+
setUnit('metric');
64+
setResult(null);
65+
};
66+
67+
return (
68+
<div className="play-details">
69+
<PlayHeader play={props} />
70+
<div className="play-details-body">
71+
<div className="bmr-tdee-container">
72+
<h2 className="bmr-tdee-title">BMR & TDEE Calculator</h2>
73+
<p className="bmr-tdee-subtitle">
74+
Calculate your Basal Metabolic Rate and Total Daily Energy Expenditure
75+
</p>
76+
77+
<div className="bmr-tdee-form">
78+
{/* Unit Toggle */}
79+
<div className="bmr-tdee-field">
80+
<label className="bmr-tdee-label">Unit System</label>
81+
<div className="bmr-tdee-toggle-group">
82+
<button
83+
className={`bmr-tdee-toggle-btn ${unit === 'metric' ? 'active' : ''}`}
84+
onClick={() => setUnit('metric')}
85+
type="button"
86+
>
87+
Metric (kg/cm)
88+
</button>
89+
<button
90+
className={`bmr-tdee-toggle-btn ${unit === 'imperial' ? 'active' : ''}`}
91+
onClick={() => setUnit('imperial')}
92+
type="button"
93+
>
94+
Imperial (lbs/in)
95+
</button>
96+
</div>
97+
</div>
98+
99+
{/* Gender */}
100+
<div className="bmr-tdee-field">
101+
<label className="bmr-tdee-label">Gender</label>
102+
<div className="bmr-tdee-toggle-group">
103+
<button
104+
className={`bmr-tdee-toggle-btn ${gender === 'male' ? 'active' : ''}`}
105+
onClick={() => setGender('male')}
106+
type="button"
107+
>
108+
♂ Male
109+
</button>
110+
<button
111+
className={`bmr-tdee-toggle-btn ${gender === 'female' ? 'active' : ''}`}
112+
onClick={() => setGender('female')}
113+
type="button"
114+
>
115+
♀ Female
116+
</button>
117+
</div>
118+
</div>
119+
120+
{/* Age */}
121+
<div className="bmr-tdee-field">
122+
<label className="bmr-tdee-label" htmlFor="bmr-age">
123+
Age
124+
</label>
125+
<input
126+
className="bmr-tdee-input"
127+
id="bmr-age"
128+
min="1"
129+
max="120"
130+
placeholder="Enter your age"
131+
type="number"
132+
value={age}
133+
onChange={(e) => setAge(e.target.value)}
134+
/>
135+
</div>
136+
137+
{/* Weight */}
138+
<div className="bmr-tdee-field">
139+
<label className="bmr-tdee-label" htmlFor="bmr-weight">
140+
Weight ({unit === 'metric' ? 'kg' : 'lbs'})
141+
</label>
142+
<input
143+
className="bmr-tdee-input"
144+
id="bmr-weight"
145+
min="1"
146+
placeholder={`Enter weight in ${unit === 'metric' ? 'kg' : 'lbs'}`}
147+
type="number"
148+
value={weight}
149+
onChange={(e) => setWeight(e.target.value)}
150+
/>
151+
</div>
152+
153+
{/* Height */}
154+
<div className="bmr-tdee-field">
155+
<label className="bmr-tdee-label" htmlFor="bmr-height">
156+
Height ({unit === 'metric' ? 'cm' : 'inches'})
157+
</label>
158+
<input
159+
className="bmr-tdee-input"
160+
id="bmr-height"
161+
min="1"
162+
placeholder={`Enter height in ${unit === 'metric' ? 'cm' : 'inches'}`}
163+
type="number"
164+
value={height}
165+
onChange={(e) => setHeight(e.target.value)}
166+
/>
167+
</div>
168+
169+
{/* Activity Level */}
170+
<div className="bmr-tdee-field">
171+
<label className="bmr-tdee-label" htmlFor="bmr-activity">
172+
Activity Level
173+
</label>
174+
<select
175+
className="bmr-tdee-select"
176+
id="bmr-activity"
177+
value={activityLevel}
178+
onChange={(e) => setActivityLevel(e.target.value)}
179+
>
180+
{activityOptions.map((opt) => (
181+
<option key={opt.value} value={opt.value}>
182+
{opt.label}{opt.desc}
183+
</option>
184+
))}
185+
</select>
186+
</div>
187+
188+
{/* Buttons */}
189+
<div className="bmr-tdee-btn-group">
190+
<button className="bmr-tdee-btn bmr-tdee-btn-primary" onClick={calculateBMR} type="button">
191+
Calculate
192+
</button>
193+
<button className="bmr-tdee-btn bmr-tdee-btn-secondary" onClick={handleReset} type="button">
194+
Reset
195+
</button>
196+
</div>
197+
</div>
198+
199+
{/* Results */}
200+
{result && (
201+
<div className="bmr-tdee-results">
202+
<h3 className="bmr-tdee-results-title">Your Results</h3>
203+
<div className="bmr-tdee-results-grid">
204+
<div className="bmr-tdee-result-card bmr-tdee-card-bmr">
205+
<span className="bmr-tdee-result-label">BMR</span>
206+
<span className="bmr-tdee-result-value">{result.bmr}</span>
207+
<span className="bmr-tdee-result-unit">cal/day</span>
208+
<span className="bmr-tdee-result-desc">Calories at complete rest</span>
209+
</div>
210+
<div className="bmr-tdee-result-card bmr-tdee-card-tdee">
211+
<span className="bmr-tdee-result-label">TDEE</span>
212+
<span className="bmr-tdee-result-value">{result.tdee}</span>
213+
<span className="bmr-tdee-result-unit">cal/day</span>
214+
<span className="bmr-tdee-result-desc">Maintenance calories</span>
215+
</div>
216+
<div className="bmr-tdee-result-card bmr-tdee-card-deficit">
217+
<span className="bmr-tdee-result-label">Weight Loss</span>
218+
<span className="bmr-tdee-result-value">{result.deficit}</span>
219+
<span className="bmr-tdee-result-unit">cal/day</span>
220+
<span className="bmr-tdee-result-desc">TDEE − 500 cal deficit</span>
221+
</div>
222+
<div className="bmr-tdee-result-card bmr-tdee-card-surplus">
223+
<span className="bmr-tdee-result-label">Weight Gain</span>
224+
<span className="bmr-tdee-result-value">{result.surplus}</span>
225+
<span className="bmr-tdee-result-unit">cal/day</span>
226+
<span className="bmr-tdee-result-desc">TDEE + 500 cal surplus</span>
227+
</div>
228+
</div>
229+
230+
<div className="bmr-tdee-info">
231+
<h4>What do these numbers mean?</h4>
232+
<ul>
233+
<li>
234+
<strong>BMR</strong> — The calories your body burns at complete rest just to keep
235+
you alive (breathing, circulation, cell production).
236+
</li>
237+
<li>
238+
<strong>TDEE</strong> — Your total calories burned per day including physical
239+
activity. Eat this amount to maintain weight.
240+
</li>
241+
<li>
242+
<strong>Weight Loss</strong> — A 500 cal/day deficit leads to ~0.45 kg (1 lb)
243+
lost per week.
244+
</li>
245+
<li>
246+
<strong>Weight Gain</strong> — A 500 cal/day surplus leads to ~0.45 kg (1 lb)
247+
gained per week.
248+
</li>
249+
</ul>
250+
<p className="bmr-tdee-info-note">
251+
* Calculated using the Mifflin-St Jeor Equation, considered the most accurate BMR
252+
formula.
253+
</p>
254+
</div>
255+
</div>
256+
)}
257+
</div>
258+
</div>
259+
</div>
260+
);
261+
}
262+
263+
export default BmrTdeeCalculator;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# BMR & TDEE Calculator
2+
3+
A calculator to determine your Basal Metabolic Rate (BMR) and Total Daily Energy Expenditure (TDEE) using the Mifflin-St Jeor Equation.
4+
5+
## Play Demographic
6+
7+
- Language: js
8+
- Level: Beginner
9+
10+
## Creator Information
11+
12+
- User: aniketmishra-0
13+
- GitHub Link: https://github.com/aniketmishra-0
14+
- Blog:
15+
- Video:
16+
17+
## Implementation Details
18+
19+
This play implements a BMR & TDEE calculator with the following features:
20+
21+
- **BMR Calculation** using the Mifflin-St Jeor Equation (most accurate modern formula)
22+
- **TDEE Calculation** based on 5 activity levels
23+
- **Metric & Imperial** unit support (kg/cm and lbs/inches)
24+
- **Weight management guidance** showing calorie targets for loss/gain
25+
- Clean, responsive UI with smooth result animations
26+
27+
### Formulas Used
28+
29+
**Mifflin-St Jeor Equation:**
30+
- Male: BMR = 10 × weight(kg) + 6.25 × height(cm) − 5 × age − 5
31+
- Female: BMR = 10 × weight(kg) + 6.25 × height(cm) − 5 × age − 161
32+
33+
**TDEE = BMR × Activity Multiplier**
34+
35+
## Consideration
36+
37+
- Results are estimates and should not replace professional medical advice.
38+
39+
## Resources
40+
41+
- [Mifflin-St Jeor Equation](https://en.wikipedia.org/wiki/Basal_metabolic_rate)
Lines changed: 22 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)