├── .env
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.css
├── App.js
├── assets
├── icons
│ ├── body-part.png
│ ├── equipment.png
│ ├── gym.png
│ ├── left-arrow.png
│ ├── right-arrow.png
│ └── target.png
└── images
│ ├── Logo-1.png
│ ├── Logo.png
│ └── banner.png
├── components
├── BodyPart.js
├── Detail.js
├── ExerciseCard.js
├── ExerciseVideos.js
├── Exercises.js
├── Footer.js
├── HeroBanner.js
├── HorizontalScrollbar.js
├── Loader.js
├── Navbar.js
├── SearchExercises.js
└── SimilarExercises.js
├── index.js
├── pages
├── ExerciseDetail.js
└── Home.js
└── utils
└── fetchData.js
/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_RAPID_API_KEY=ccfcae50dcmsh5a50faecda0a98ep1de6ccjsn8465450cdbc7
2 | ESLINT_NO_DEV_ERRORS=true
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 |
17 | # local env files
18 | .env
19 | .env.local
20 | .env.development.local
21 | .env.test.local
22 | .env.production.local
23 |
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | React Exercise Application
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gym_exercises",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@emotion/react": "^11.9.0",
7 | "@emotion/styled": "^11.8.1",
8 | "@mui/icons-material": "^5.6.1",
9 | "@mui/material": "^5.6.1",
10 | "react": "^18.0.0",
11 | "react-dom": "^18.0.0",
12 | "react-horizontal-scrolling-menu": "^2.7.1",
13 | "react-loader-spinner": "^6.0.0-0",
14 | "react-router-dom": "^6.3.0",
15 | "react-scripts": "5.0.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test",
21 | "eject": "react-scripts eject"
22 | },
23 | "eslintConfig": {
24 | "extends": [
25 | "react-app",
26 | "react-app/jest"
27 | ]
28 | },
29 | "browserslist": {
30 | "production": [
31 | ">0.2%",
32 | "not dead",
33 | "not op_mini all"
34 | ],
35 | "development": [
36 | "last 1 chrome version",
37 | "last 1 firefox version",
38 | "last 1 safari version"
39 | ]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: 'Josefin Sans';
3 | background-color: #FFFAFB;
4 | }
5 |
6 | * {
7 | padding: 0px;
8 | margin: 0px;
9 | box-sizing: border-box;
10 |
11 | }
12 |
13 | ::-webkit-scrollbar {
14 | width: 0px;
15 | }
16 |
17 | .right-arrow,
18 | .left-arrow {
19 | cursor: pointer;
20 | background: transparent;
21 | outline: none;
22 | border: none;
23 | display: flex;
24 | justify-content: center;
25 | align-items: center;
26 | color: #FF2625;
27 | font-size: 25px;
28 | border-radius: 4px;
29 | position: absolute;
30 | bottom: -20px;
31 | right: 80px;
32 | transform: scale(1, 1);
33 | transition: 0.3s all ease-in-out;
34 | }
35 |
36 | .right-arrow {
37 | right: 140px;
38 | }
39 |
40 | .right-arrow:hover,
41 | .left-arrow:hover {
42 | transform: scale(1.3, 1.3);
43 | }
44 |
45 | .react-horizontal-scrolling-menu--wrapper {
46 | width: 100%;
47 | display: flex;
48 | flex-wrap: wrap;
49 | }
50 |
51 | .detail-image {
52 | width: 729px;
53 | height: 742px;
54 | }
55 |
56 | .hero-banner-img {
57 | position: absolute;
58 | right: 40px;
59 | top: 0px;
60 | width: 700px;
61 | height: 900px;
62 | margin-top: -330px;
63 |
64 | }
65 |
66 | .exercise-card {
67 | width: 400px;
68 | height: 445px;
69 | background: #fff;
70 | border-top: 4px solid #FF2625;
71 | border-bottom-left-radius: 20px;
72 | text-decoration: none;
73 | display: flex;
74 | justify-content: space-between;
75 | flex-direction: column;
76 | padding-bottom: 10px;
77 | transform: scale(1, 1);
78 | transition: 0.3s all ease-in-out;
79 | }
80 |
81 | .exercise-card img {
82 | height: 326px;
83 | }
84 |
85 | .bodyPart-card {
86 | transform: scale(1, 1);
87 | transition: 0.3s all ease-in-out;
88 | }
89 |
90 | .exercise-card:hover,
91 | .bodyPart-card:hover {
92 | transform: scale(1.1, 1.1);
93 | }
94 |
95 | .search-btn:hover {
96 | color: #FF2625 !important;
97 | border: 1px solid #FF2625 !important;
98 | }
99 |
100 | .exercise-video {
101 | display: flex;
102 | flex-direction: column;
103 | gap: 24px;
104 | width: 387px;
105 | height: 381px;
106 | text-decoration: none;
107 | }
108 |
109 | @media screen and (max-width:1200px) {
110 | .detail-image {
111 | width: 300px;
112 | height: 300px;
113 | }
114 |
115 |
116 | .react-horizontal-scrolling-menu--scroll-container {
117 | width: 500px;
118 | }
119 |
120 | .left-arrow,
121 | .right-arrow {
122 | position: static !important;
123 | }
124 |
125 | .hero-banner-img {
126 | display: none;
127 | }
128 |
129 | .exercise-card {
130 | width: 320px;
131 | }
132 |
133 | .exercise-video {
134 | width: 320px;
135 | height: 300px;
136 | }
137 |
138 | }
139 |
140 | @media screen and (max-width:400px) {
141 | .exercise-card {
142 | width: 280px;
143 | }
144 | }
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route, Routes } from 'react-router-dom';
3 | import { Box } from '@mui/material';
4 |
5 | import './App.css';
6 | import ExerciseDetail from './pages/ExerciseDetail';
7 | import Home from './pages/Home';
8 | import Navbar from './components/Navbar';
9 | import Footer from './components/Footer';
10 |
11 | const App = () => (
12 |
13 |
14 |
15 | } />
16 | } />
17 |
18 |
19 |
20 | );
21 |
22 | export default App
--------------------------------------------------------------------------------
/src/assets/icons/body-part.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/src/assets/icons/body-part.png
--------------------------------------------------------------------------------
/src/assets/icons/equipment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/src/assets/icons/equipment.png
--------------------------------------------------------------------------------
/src/assets/icons/gym.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/src/assets/icons/gym.png
--------------------------------------------------------------------------------
/src/assets/icons/left-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/src/assets/icons/left-arrow.png
--------------------------------------------------------------------------------
/src/assets/icons/right-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/src/assets/icons/right-arrow.png
--------------------------------------------------------------------------------
/src/assets/icons/target.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/src/assets/icons/target.png
--------------------------------------------------------------------------------
/src/assets/images/Logo-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/src/assets/images/Logo-1.png
--------------------------------------------------------------------------------
/src/assets/images/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/src/assets/images/Logo.png
--------------------------------------------------------------------------------
/src/assets/images/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emredkyc/exercise_app/655858d4065378417777e37d780b42809d0cdfa3/src/assets/images/banner.png
--------------------------------------------------------------------------------
/src/components/BodyPart.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Stack, Typography } from "@mui/material";
3 | import Icon from "../assets/icons/gym.png";
4 |
5 | const BodyPart = ({ item, setBodyPart, bodyPart }) => (
6 | {
32 | setBodyPart(item);
33 | window.scrollTo({ top: 1800, left: 100, behavior: "smooth" });
34 | }}
35 | >
36 |
37 |
44 | {" "}
45 | {item}
46 |
47 |
48 | );
49 |
50 | export default BodyPart
--------------------------------------------------------------------------------
/src/components/Detail.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Typography, Stack, Button } from "@mui/material";
3 |
4 | import BodyPartImage from "../assets/icons/body-part.png";
5 | import TargetImage from "../assets/icons/target.png";
6 | import EquipmentImage from "../assets/icons/equipment.png";
7 |
8 | const Detail = ({ exerciseDetail }) => {
9 | const { bodyPart, gifUrl, name, target, equipment } = exerciseDetail;
10 |
11 | const extraDetail = [
12 | {
13 | icon: BodyPartImage,
14 | name: bodyPart,
15 | },
16 | {
17 | icon: TargetImage,
18 | name: target,
19 | },
20 | {
21 | icon: EquipmentImage,
22 | name: equipment,
23 | },
24 | ];
25 |
26 | return (
27 |
31 |
32 |
33 |
38 | {name}
39 |
40 |
44 | Exercises keep you strong.{" "}
45 | {name} bup is one
46 | of the best
exercises to target your {target}. It will help you
47 | improve your
mood and gain energy.
48 |
49 | {extraDetail?.map((item) => (
50 |
51 |
65 |
69 | {item.name}
70 |
71 |
72 | ))}
73 |
74 |
75 | );
76 | };
77 |
78 | export default Detail
--------------------------------------------------------------------------------
/src/components/ExerciseCard.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import { Button, Stack, Typography } from "@mui/material";
4 |
5 | const ExerciseCard = ({ exercise }) => (
6 |
7 |
8 |
9 |
21 |
33 |
34 |
43 | {exercise.name}
44 |
45 |
46 | );
47 |
48 | export default ExerciseCard
--------------------------------------------------------------------------------
/src/components/ExerciseVideos.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Typography, Box, Stack } from "@mui/material";
3 | import Loader from "./Loader";
4 |
5 | const ExerciseVideos = ({ exerciseVideos, name }) => {
6 | if (!exerciseVideos.length) return ;
7 |
8 | return (
9 |
10 |
16 | Watch{" "}
17 |
18 | {name}
19 | {" "}
20 | exercise videos
21 |
22 |
28 | {exerciseVideos?.slice(0, 3)?.map((item, index) => (
29 |
36 |
41 |
42 |
47 | {item.video.title}
48 |
49 |
50 | {item.video.channelName}
51 |
52 |
53 |
54 | ))}
55 |
56 |
57 | );
58 | };
59 |
60 | export default ExerciseVideos
--------------------------------------------------------------------------------
/src/components/Exercises.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import Pagination from "@mui/material/Pagination";
3 | import { Box, Stack, Typography } from "@mui/material";
4 |
5 | import { exerciseOptions, fetchData } from "../utils/fetchData";
6 | import ExerciseCard from "./ExerciseCard";
7 | import Loader from "./Loader";
8 |
9 | const Exercises = ({ exercises, setExercises, bodyPart }) => {
10 | const [currentPage, setCurrentPage] = useState(1);
11 | const [exercisesPerPage] = useState(6);
12 |
13 | useEffect(() => {
14 | const fetchExercisesData = async () => {
15 | let exercisesData = [];
16 |
17 | if (bodyPart === "all") {
18 | exercisesData = await fetchData(
19 | "https://exercisedb.p.rapidapi.com/exercises",
20 | exerciseOptions
21 | );
22 | } else {
23 | exercisesData = await fetchData(
24 | `https://exercisedb.p.rapidapi.com/exercises/bodyPart/${bodyPart}`,
25 | exerciseOptions
26 | );
27 | }
28 |
29 | setExercises(exercisesData);
30 | };
31 |
32 | fetchExercisesData();
33 | }, [bodyPart]);
34 |
35 | // Pagination
36 | const indexOfLastExercise = currentPage * exercisesPerPage;
37 | const indexOfFirstExercise = indexOfLastExercise - exercisesPerPage;
38 | const currentExercises = exercises.slice(
39 | indexOfFirstExercise,
40 | indexOfLastExercise
41 | );
42 |
43 | const paginate = (event, value) => {
44 | setCurrentPage(value);
45 |
46 | window.scrollTo({ top: 1800, behavior: "smooth" });
47 | };
48 |
49 | if (!currentExercises.length) return ;
50 |
51 | return (
52 |
53 |
59 | Showing Results
60 |
61 |
67 | {currentExercises.map((exercise, idx) => (
68 |
69 | ))}
70 |
71 |
72 | {exercises.length > 9 && (
73 |
82 | )}
83 |
84 |
85 | );
86 | };
87 |
88 | export default Exercises
--------------------------------------------------------------------------------
/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Box, Stack, Typography } from "@mui/material";
3 | import Logo from "../assets/images/Logo-1.png";
4 |
5 | const Footer = () => (
6 |
7 |
14 |
15 |
16 |
23 | Made for Sude ❤️
24 |
25 |
26 | );
27 |
28 | export default Footer
--------------------------------------------------------------------------------
/src/components/HeroBanner.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Box, Stack, Typography } from "@mui/material";
3 |
4 | import HeroBannerImage from "../assets/images/banner.png";
5 |
6 | const HeroBanner = () => (
7 |
12 |
13 | Exercise Club
14 |
15 |
21 | Sweat, Smile
22 | And Repeat
23 |
24 |
25 | Check out the most effective exercises personalized to you
26 |
27 |
28 |
43 | Explore Exercises
44 |
45 |
46 |
55 | Exercise
56 |
57 |
58 |
59 | );
60 |
61 | export default HeroBanner
--------------------------------------------------------------------------------
/src/components/HorizontalScrollbar.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { ScrollMenu, VisibilityContext } from "react-horizontal-scrolling-menu";
3 | import { Box, Typography } from "@mui/material";
4 |
5 | import ExerciseCard from "./ExerciseCard";
6 | import BodyPart from "./BodyPart";
7 | import RightArrowIcon from "../assets/icons/right-arrow.png";
8 | import LeftArrowIcon from "../assets/icons/left-arrow.png";
9 |
10 | const LeftArrow = () => {
11 | const { scrollPrev } = useContext(VisibilityContext);
12 |
13 | return (
14 | scrollPrev()} className="right-arrow">
15 |
16 |
17 | );
18 | };
19 |
20 | const RightArrow = () => {
21 | const { scrollNext } = useContext(VisibilityContext);
22 |
23 | return (
24 | scrollNext()} className="left-arrow">
25 |
26 |
27 | );
28 | };
29 |
30 | const HorizontalScrollbar = ({ data, bodyParts, setBodyPart, bodyPart }) => (
31 |
32 | {data.map((item) => (
33 |
39 | {bodyParts ? (
40 |
41 | ) : (
42 |
43 | )}
44 |
45 | ))}
46 |
47 | );
48 |
49 | export default HorizontalScrollbar;
50 |
--------------------------------------------------------------------------------
/src/components/Loader.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Stack } from "@mui/material";
3 | import { InfinitySpin } from "react-loader-spinner";
4 |
5 | const Loader = () => (
6 |
12 |
13 |
14 | );
15 |
16 | export default Loader
--------------------------------------------------------------------------------
/src/components/Navbar.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import { Stack } from "@mui/material";
4 |
5 | import Logo from "../assets/images/Logo.png";
6 |
7 | const Navbar = () => (
8 |
18 |
19 |
24 |
25 |
32 |
40 | Home
41 |
42 |
43 | Exercises
44 |
45 |
46 |
47 | );
48 |
49 | export default Navbar
--------------------------------------------------------------------------------
/src/components/SearchExercises.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { Box, Button, Stack, TextField, Typography } from "@mui/material";
3 |
4 | import { exerciseOptions, fetchData } from "../utils/fetchData";
5 | import HorizontalScrollbar from "./HorizontalScrollbar";
6 |
7 | const SearchExercises = ({ setExercises, bodyPart, setBodyPart }) => {
8 | const [search, setSearch] = useState("");
9 | const [bodyParts, setBodyParts] = useState([]);
10 |
11 | useEffect(() => {
12 | const fetchExercisesData = async () => {
13 | const bodyPartsData = await fetchData(
14 | "https://exercisedb.p.rapidapi.com/exercises/bodyPartList",
15 | exerciseOptions
16 | );
17 |
18 | setBodyParts(["all", ...bodyPartsData]);
19 | };
20 |
21 | fetchExercisesData();
22 | }, []);
23 |
24 | const handleSearch = async () => {
25 | if (search) {
26 | const exercisesData = await fetchData(
27 | "https://exercisedb.p.rapidapi.com/exercises",
28 | exerciseOptions
29 | );
30 |
31 | const searchedExercises = exercisesData.filter(
32 | (item) =>
33 | item.name.toLowerCase().includes(search) ||
34 | item.target.toLowerCase().includes(search) ||
35 | item.equipment.toLowerCase().includes(search) ||
36 | item.bodyPart.toLowerCase().includes(search)
37 | );
38 |
39 | window.scrollTo({ top: 1800, left: 100, behavior: "smooth" });
40 |
41 | setSearch("");
42 | setExercises(searchedExercises);
43 | }
44 | };
45 |
46 | return (
47 |
48 |
54 | Awesome Exercises You
Should Know
55 |
56 |
57 | setSearch(e.target.value.toLowerCase())}
67 | placeholder="Search Exercises"
68 | type="text"
69 | />
70 |
86 |
87 |
88 |
94 |
95 |
96 | );
97 | };
98 |
99 | export default SearchExercises
--------------------------------------------------------------------------------
/src/components/SimilarExercises.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Typography, Box, Stack } from "@mui/material";
3 |
4 | import HorizontalScrollbar from "./HorizontalScrollbar";
5 | import Loader from "./Loader";
6 |
7 | const SimilarExercises = ({ targetMuscleExercises, equipmentExercises }) => (
8 |
9 |
15 | Similar{" "}
16 |
17 | Target Muscle
18 | {" "}
19 | exercises
20 |
21 |
22 | {targetMuscleExercises.length !== 0 ? (
23 |
24 | ) : (
25 |
26 | )}
27 |
28 |
38 | Similar{" "}
39 |
40 | Equipment
41 | {" "}
42 | exercises
43 |
44 |
45 | {equipmentExercises.length !== 0 ? (
46 |
47 | ) : (
48 |
49 | )}
50 |
51 |
52 | );
53 |
54 | export default SimilarExercises
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import { BrowserRouter } from "react-router-dom";
4 |
5 | import App from "./App";
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 |
9 | root.render(
10 |
11 |
12 |
13 |
14 |
15 | );
--------------------------------------------------------------------------------
/src/pages/ExerciseDetail.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { useParams } from "react-router-dom";
3 | import { Box } from "@mui/material";
4 |
5 | import { exerciseOptions, fetchData, youtubeOptions } from "../utils/fetchData";
6 | import Detail from "../components/Detail";
7 | import ExerciseVideos from "../components/ExerciseVideos";
8 | import SimilarExercises from "../components/SimilarExercises";
9 |
10 | const ExerciseDetail = () => {
11 | const [exerciseDetail, setExerciseDetail] = useState({});
12 | const [exerciseVideos, setExerciseVideos] = useState([]);
13 | const [targetMuscleExercises, setTargetMuscleExercises] = useState([]);
14 | const [equipmentExercises, setEquipmentExercises] = useState([]);
15 | const { id } = useParams();
16 |
17 | useEffect(() => {
18 | window.scrollTo({ top: 0, behavior: "smooth" });
19 |
20 | const fetchExercisesData = async () => {
21 | const exerciseDbUrl = "https://exercisedb.p.rapidapi.com";
22 | const youtubeSearchUrl =
23 | "https://youtube-search-and-download.p.rapidapi.com";
24 |
25 | const exerciseDetailData = await fetchData(
26 | `${exerciseDbUrl}/exercises/exercise/${id}`,
27 | exerciseOptions
28 | );
29 | setExerciseDetail(exerciseDetailData);
30 |
31 | const exerciseVideosData = await fetchData(
32 | `${youtubeSearchUrl}/search?query=${exerciseDetailData.name} exercise`,
33 | youtubeOptions
34 | );
35 | setExerciseVideos(exerciseVideosData.contents);
36 |
37 | const targetMuscleExercisesData = await fetchData(
38 | `${exerciseDbUrl}/exercises/target/${exerciseDetailData.target}`,
39 | exerciseOptions
40 | );
41 | setTargetMuscleExercises(targetMuscleExercisesData);
42 |
43 | const equimentExercisesData = await fetchData(
44 | `${exerciseDbUrl}/exercises/equipment/${exerciseDetailData.equipment}`,
45 | exerciseOptions
46 | );
47 | setEquipmentExercises(equimentExercisesData);
48 | };
49 |
50 | fetchExercisesData();
51 | }, [id]);
52 |
53 | if (!exerciseDetail) return No Data
;
54 |
55 | return (
56 |
57 |
58 |
62 |
66 |
67 | );
68 | };
69 |
70 | export default ExerciseDetail
--------------------------------------------------------------------------------
/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { Box } from "@mui/material";
3 |
4 | import Exercises from "../components/Exercises";
5 | import SearchExercises from "../components/SearchExercises";
6 | import HeroBanner from "../components/HeroBanner";
7 |
8 | const Home = () => {
9 | const [exercises, setExercises] = useState([]);
10 | const [bodyPart, setBodyPart] = useState("all");
11 |
12 | return (
13 |
14 |
15 |
20 |
25 |
26 | );
27 | };
28 |
29 | export default Home
--------------------------------------------------------------------------------
/src/utils/fetchData.js:
--------------------------------------------------------------------------------
1 | export const exerciseOptions = {
2 | method: "GET",
3 | headers: {
4 | "X-RapidAPI-Host": "exercisedb.p.rapidapi.com",
5 | "X-RapidAPI-Key": process.env.REACT_APP_RAPID_API_KEY,
6 | },
7 | };
8 |
9 | export const youtubeOptions = {
10 | method: "GET",
11 | headers: {
12 | "X-RapidAPI-Host": "youtube-search-and-download.p.rapidapi.com",
13 | "X-RapidAPI-Key": process.env.REACT_APP_RAPID_API_KEY,
14 | },
15 | };
16 |
17 | export const fetchData = async (url, options) => {
18 | const res = await fetch(url, options);
19 | const data = await res.json();
20 |
21 | return data;
22 | }
23 |
--------------------------------------------------------------------------------