I am working on fitness app using react js where there is a list of bodyparts. I wanted to have a seperate image for each body part but getting same image for all
BodyPart.js
import React,{useState} from 'react'
import { Stack, Typography } from '@mui/material';
const BodyPart = ({ item, setBodyPart, bodyPart}) => {
const image = require(`../assets/images/bodypart/${bodyPart}.jpg`);
return (
<Stack type="button"
alignItems="center"
justifyContent="center"
className="bodyPart-card"
sx={{
borderTop: bodyPart === item ? '4px solid #ff2625' : '',
backgroundColor: "#fff",
borderBottomLeftRadius: '20px',
width: '270px',
height: '280px ',
cursor: 'pointer',
gap: '47px'
}}
onClick={()=>{
setBodyPart(item);
window.scrollTo({top:1800, left:100, behavior:'smooth'})
}}
>
<img
src= {image}
alt='dumbell'
style={{ width: '70px', height: '70px' }}
/>
<Typography fontSize="24px" fontWeight="bold" color="#3A1212">
{item}
</Typography>
</Stack>
)
}
export default BodyPart
HorizontalScroll.js
import React, { useContext } from 'react'
import { Box, Typography } from '@mui/material';
import BodyPart from './BodyPart';
import { ScrollMenu, VisibilityContext } from 'react-horizontal-scrolling-menu';
import RightArrowIcon from '../assets/icons/right-arrow.png';
import LeftArrowIcon from '../assets/icons/left-arrow.png';
import ExerciseCard from './ExerciseCard';
const LeftArrow = () => {
const { scrollPrev } = useContext(VisibilityContext);
return (
<Typography onClick={() => scrollPrev()} className="right-arrow">
<img src={LeftArrowIcon} alt="right-arrow" />
</Typography>
);
};
const RightArrow = () => {
const { scrollNext } = useContext(VisibilityContext);
return (
<Typography onClick={() => scrollNext()} className="left-arrow">
<img src={RightArrowIcon} alt="right-arrow" />
</Typography>
);
};
const HorizontalScrollbar = ({ data, bodyParts, setBodyPart, bodyPart}) => {
return (<ScrollMenu LeftArrow={LeftArrow} RightArrow={RightArrow}>
{data.map((item) => (
<Box
key={item.id || item}
itemId={item.id || item}
title={item.id || item}
m="0 40px"
>
{bodyParts ? <BodyPart item={item}
setBodyPart={setBodyPart} bodyPart={bodyPart}/>: <ExerciseCard exercise={item}/> }
</Box>
))}
</ScrollMenu>
)
}
export default HorizontalScrollbar
SearchExercises.js
import React,{useEffect, useState} from 'react'
import {Box, Button, Stack,TextField, Typography} from '@mui/material';
import {fetchData, exercisesOptions} from '../utils/fetchData';
import HorizontalScrollbar from './HorizontalScrollbar';
import images from './images'
const SearchExercises = ({setExercises,bodyPart,setBodyPart}) => {
const [search, setSearch] = useState('');
const [bodyParts, setBodyParts] = useState([])
useEffect(()=>{
const fetchExercisesData = async () => {
const bodyPartData = await fetchData('https://exercisedb.p.rapidapi.com/exercises/bodyPartList',
exercisesOptions);
setBodyParts(['all',...bodyPartData]);
}
fetchExercisesData();
}, [])
const handleSearch = async () => {
if(search) {
const exercisesData = await fetchData(
'https://exercisedb.p.rapidapi.com/exercises',
exercisesOptions
);
const searchedExercises = exercisesData.filter(
(item) => item.name.toLowerCase().includes(search)
|| item.target.toLowerCase().includes(search)
|| item.equipment.toLowerCase().includes(search)
|| item.bodyPart.toLowerCase().includes(search),
);
setSearch('');
setExercises(searchedExercises);
}
}
return (
<Stack alignItems="center" mt="37px"
justifyContent="center" p="20px">
<Typography fontWeight={700}
sx={{fontSize:{lg: '44px', xs:'30px'}}}
mb="50px" textAlign="center">
Awesome Exercises You <br/>
Should know
</Typography>
<Box position="relative" mb="72px">
<TextField
sx={{
input: {fontWeight: '700',
border :'none',
borderRadius:'4px'
},
width :{lg:'800px', xs:'350px'},
backgroundColor : "#fff",
borderRadius:'40px'
}}
height="76px"
value={search}
onChange={(e)=>{setSearch(e.target.value.toLowerCase())}}
placeholder="Search Exercises"
type="text" />
<Button className="search-btn"
sx={{
bgcolor:'#FF2625',
color:"#fff",
textTransform :'none',
width:{lg:'175px', xs:'80px'},
fontSize :{lg:'20px', xs:'14px'},
height:'56px',
position : 'absolute',
right:0
}} onClick={handleSearch}>
Search
</Button>
</Box>
<Box sx={{position:'relative', width:'100%', p:'20px'}}>
<HorizontalScrollbar data={bodyParts} bodyParts
setBodyPart={setBodyPart} bodyPart={bodyPart} isBodyParts/>
</Box>
</Stack>
)
}
export default SearchExercises
I wanted to have separate image for each body part. I tried to create array of all bodyParts data with images and name but that also didn't work in this scenarios.
This "https://exercisedb.p.rapidapi.com/exercises/bodyPartList" API returns below data
I have already render the required data as individual box here. I just wanted to apply image for each bodyPart separately currently it is applying same image
There is some bodyPart
prop being passed to SearchExercises
all the way through HorizontalScrollbar
to BodyPart
... which is the same value for all values the HorizontalScrollbar
component is mapping.
The HorizontalScrollbar
component's data
prop is the body parts data that should be mapped, not the passed bodyPart
prop.
SearchExercises
const SearchExercises = ({ activeBodyPart, setExercises, setBodyPart }) => {
...
const [bodyParts, setBodyParts] = useState([]);
useEffect(() => {
const fetchExercisesData = async () => {
const bodyPartData = await fetchData(
'https://exercisedb.p.rapidapi.com/exercises/bodyPartList',
exercisesOptions
);
setBodyParts(['all', ...bodyPartData]);
}
fetchExercisesData();
}, []);
...
return (
...
<HorizontalScrollbar
data={bodyParts}
bodyParts
setBodyPart={setBodyPart}
activeBodyPart={activeBodyPart}
/>
...
);
HorizontalScrollbar
const HorizontalScrollbar = ({ activeBodyPart, data, bodyParts, setBodyPart }) => {
return (
<ScrollMenu LeftArrow={LeftArrow} RightArrow={RightArrow}>
{data.map((bodyPart) => (
<Box
key={bodyPart}
itemId={bodyPart}
title={bodyPart}
m="0 40px"
>
{bodyParts
? (
<BodyPart
activeBodyPart={activeBodyPart}
setBodyPart={setBodyPart}
bodyPart={bodyPart}
/>
) : <ExerciseCard exercise={bodyPart} />
}
</Box>
))}
</ScrollMenu>
)
}
BodyPart
const BodyPart = ({ activeBodyPart, setBodyPart, bodyPart}) => {
const image = require(`../assets/images/bodypart/${bodyPart}.jpg`);
return (
<Stack
type="button"
alignItems="center"
justifyContent="center"
className="bodyPart-card"
sx={{
borderTop: bodyPart === activeBodyPart ? '4px solid #ff2625' : '',
backgroundColor: "#fff",
borderBottomLeftRadius: '20px',
width: '270px',
height: '280px ',
cursor: 'pointer',
gap: '47px'
}}
onClick={() => {
setBodyPart(bodyPart);
window.scrollTo({ top: 1800, left: 100, behavior: 'smooth' });
}}
>
<img
src={image}
alt='dumbell'
style={{ width: '70px', height: '70px' }}
/>
<Typography fontSize="24px" fontWeight="bold" color="#3A1212">
{bodyPart}
</Typography>
</Stack>
);
}