Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Riz committed Jan 10, 2024
1 parent 3c75955 commit 412f23f
Show file tree
Hide file tree
Showing 32 changed files with 439 additions and 85 deletions.
60 changes: 26 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,38 @@
# Getting Started with Create React App
# Frontend Mentor - Body Mass Index Calculator solution

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
This is a solution to the [Body Mass Index Calculator challenge on Frontend Mentor](https://www.frontendmentor.io/challenges/body-mass-index-calculator-brrBkfSz1T). Frontend Mentor challenges help you improve your coding skills by building realistic projects.

## Available Scripts
## Table of contents
- [The challenge](#the-challenge)
- [Screenshot](#screenshot)
- [Links](#links)
- [Built with](#built-with)

In the project directory, you can run:
### The challenge

### `npm start`
Users should be able to:

Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
- Select whether they want to use metric or imperial units
- Enter their height and weight
- See their BMI result, with their weight classification and healthy weight range
- View the optimal layout for the interface depending on their device's screen size
- See hover and focus states for all interactive elements on the page

The page will reload if you make edits.\
You will also see any lint errors in the console.
### Screenshot

### `npm test`
![myScreenshot](./src/screenshot.png)

Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### Links

### `npm run build`
- [Solution URL](https://github.com/mriyaz/Body-mass-index-calculator-challenge)
- [Live Site URL](https://Body-mass-index-calculator-challenge.vercel.app/)

Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
### Built with

The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
- HTML
- CSS
- Flexbox
- TypeScript
- [React](https://reactjs.org/) - JS library
- Tailwind CSS

See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.

### `npm run eject`

**Note: this is a one-way operation. Once you `eject`, you can’t go back!**

If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.

Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.

You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.

## Learn More

You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).

To learn React, check out the [React documentation](https://reactjs.org/).
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,10 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"autoprefixer": "^10.4.16",
"postcss": "^8.4.32",
"tailwindcss": "^3.4.0"
}
}
6 changes: 6 additions & 0 deletions postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
31 changes: 15 additions & 16 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import React from 'react';
import logo from './logo.svg';
import Header from './components/Header';
import BmiCalculator from './components/BmiCalculator';
import BmiMeaning from './components/BmiMeaning';
import BmiTips from './components/BmiTips';
import BmiLimitations from './components/BmiLimitations';

import './App.css';

function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
<div >
<div className="xl:flex xl:items-center">
<Header />
<BmiCalculator />
</div>
<BmiMeaning />
<BmiTips />
<BmiLimitations />

</div>
);
}
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes
File renamed without changes
199 changes: 199 additions & 0 deletions src/components/BmiCalculator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// Import statements
import React, { useState, useEffect } from 'react';
import '../App.css'; // Make sure to have an App.css for additional styling


// BMIFormState interface definition
interface BMIFormState {
system: 'metric' | 'imperial';
height: { cm: number; feet: number; inches: number };
weight: { kg: number; stones: number; pounds: number };
bmi?: number;
category?: string;
idealWeight?: string;
}

// BmiCalculator functional component
const BmiCalculator: React.FC = () => {
// State initialization for formState
const [formState, setFormState] = useState<BMIFormState>({
// Initial state setup
system: 'imperial',
height: { cm: 0, feet: 0, inches: 0 },
weight: { kg: 0, stones: 0, pounds: 0 }
});

// useEffect hook for BMI calculation
useEffect(() => {
// Function to calculate BMI
const calculateBMI = () => {
//Variables
const { system, height, weight } = formState;
let bmi = 0;

// BMI calculation for metric system
if (system === 'metric') {
if (height.cm > 0 && weight.kg > 0) {
bmi = weight.kg / ((height.cm / 100) ** 2);
}
} else {
// BMI calculation for imperial system
const totalHeightInInches = height.feet * 12 + height.inches;
const totalWeightInPounds = weight.stones * 14 + weight.pounds;
if (totalHeightInInches > 0 && totalWeightInPounds > 0) {
bmi = (totalWeightInPounds / (totalHeightInInches ** 2)) * 703;
}
}

// Setting the calculated BMI, category, and ideal weight in state
const category = getBMICategory(bmi);
const idealWeight = getIdealWeight(height, system);
setFormState(prev => ({ ...prev, bmi, category, idealWeight }));
}

// Call the function to calculate BMI
calculateBMI();

}, [formState.height, formState.weight, formState.system]);

// Function to handle measurement system change (metric/imperial)
const handleSystemChange = (system: 'metric' | 'imperial') => {
// Update state based on selected system & reset height & weight
setFormState({
...formState, system, height: { cm: 0, feet: 0, inches: 0 },
weight: { kg: 0, stones: 0, pounds: 0 }
})

};

// Function to handle input changes for height and weight fields
const handleInputChange = (name: string, value: number) => {
// Update state based on input change
setFormState((prev) => ({
...prev,
height: { ...prev.height, [name]: value },
weight: { ...prev.weight, [name]: value },
}))
};

// Function to render individual input fields
const renderInputField = (
name: string,
label: string,
value: number,
onChange: (name: string, value: number) => void
) => (
// Return JSX for input field
<div className="flex flex-row items-center mb-3 border-2 border-gray-300 rounded-md hover:border-blue-500 focus-within:border-blue-500 flex-grow shrink-0 basis-1/4 p-1">
<input
type="number"
name={name}
className="p-2 rounded focus:outline-none border-none w-full text-xl font-semibold"
value={value}
onChange={(e) => onChange(name, parseFloat(e.target.value))}
/>
<span className="p-2 text-xl font-semibold">{label}</span>
</div>
);

// Function to get BMI category
const getBMICategory = (bmi: number): string => {
// Determine and return BMI category
if (bmi < 18.5) return 'Underweight';
if (bmi >= 18.5 && bmi < 24.9) return 'Healthy weight';
if (bmi >= 25 && bmi < 29.9) return 'Overweight';
return 'Obesity';
};

// Function to get ideal weight range
const getIdealWeight = (height: { feet: number; inches: number; cm: number }, system: 'metric' | 'imperial'): string => {
// Calculate and return ideal weight range
const idealBMI = 22.5;
if (system === 'metric' && height.cm) {
const idealKg = idealBMI * ((height.cm / 100) ** 2);
return `${(idealKg - 5).toFixed(1)}kg - ${(idealKg + 5).toFixed(1)}kg`;
} else if (height.feet && height.inches) {
const totalHeightInInches = height.feet * 12 + height.inches;
const idealLbs = idealBMI * (totalHeightInInches ** 2) / 703;
const idealSt = idealLbs / 14;
return `${Math.floor(idealSt)}st ${Math.round(idealLbs % 14)}lbs - ${Math.floor(idealSt + 0.5)}st ${Math.round((idealLbs + 10) % 14)}lbs`;
}
return '';
};

// Component JSX return
return (
// Main container for the BMI Calculator
<div className="container mx-auto p-4 shadow-lg rounded-lg sm:-mt-60
bg-white xl:absolute xl:right-40 xl:top-80 xl:w-[40%] xl:rounded-3xl">
{/* // Heading for the BMI Calculator */}
<h1 className="text-xl font-bold mb-4">Enter your details below</h1>

{/* // Radio buttons for system selection (Metric and Imperial) */}
<div className='flex justify-around mb-6 text-xs'>
{/* // Radio button for Metric system */}
<label className="inline-flex items-center mt-3 gap-3">
<input type="radio" name="system" className='form-radio h-5 w-5 text-blue-600' checked={formState.system === 'metric'} onChange={() => handleSystemChange('metric')} />
<span className="ml-2 text-gray-700 font-semibold">Metric</span>
</label>
{/* // Radio button for Imperial system */}
<label className="inline-flex items-center mt-3 gap-3">
<input type="radio" name="system" className='form-radio h-5 w-5 text-blue-600' checked={formState.system === 'imperial'} onChange={() => handleSystemChange('imperial')} />
<span className="ml-2 text-gray-700 font-semibold">Imperial</span>
</label>
</div>

{/* // Conditional rendering of input fields based on selected measurement system */}
{formState.system === 'metric' ? (
// Input fields for Metric system
<div className="flex flex-col xl:flex-row xl:gap-2">
<div> <span className='text-xs text-gray-500'>Height</span>
{renderInputField('cm', 'cm', formState.height.cm, handleInputChange)}
</div>
<div>
<span className='text-xs text-gray-500'>Weight</span>
{renderInputField('kg', 'kg', formState.weight.kg, handleInputChange)}
</div>
</div>
) : (

<div className="">
<span className='text-xs text-gray-500'>Height</span>
<div className="flex flex-row justify-between items-center gap-2">
{renderInputField('feet', 'ft', formState.height.feet, handleInputChange)}
{renderInputField('inches', 'in', formState.height.inches, handleInputChange)}
</div>
<span className='text-xs text-gray-500'>Weight</span>
<div className="flex flex-row justify-between items-center gap-2">
{renderInputField('stones', 'st', formState.weight.stones, handleInputChange)}
{renderInputField('pounds', 'lbs', formState.weight.pounds, handleInputChange)}
</div>
</div>
)}

{/* // Result display section showing BMI, category, and ideal weight range */}
<div className="bg-blue-500 text-white p-8 rounded-xl mt-4
sm:rounded-r-full
">
{/* // Conditional rendering for displaying BMI result or welcome message */}
{formState.bmi !== 0 && formState.bmi !== undefined && formState.bmi != null ? (
<div className='text-center sm:text-left'>
Your BMI is...
<h1 className='text-4xl mb-3 font-semibold'>{formState.bmi.toFixed(2)}</h1>
<p className='text-xs'> Your BMI suggests that you are {formState.category}. Your ideal weight is between {formState.idealWeight}.</p>

</div>
) : (
<div className='text-center sm:text-left'>
<h1 className='text-xl mb-3'>Welcome!</h1>
<p className='text-xs'> Enter your height and weight, and you'll see your BMI result here.</p>
</div>
)}
</div>
</div>
);
};

// Export the BmiCalculator component
export default BmiCalculator;
Loading

0 comments on commit 412f23f

Please sign in to comment.