Open In App

Workout Planner using MERN Stack

Last Updated : 18 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

With a busy schedule, it is very important to prioritize our health and fitness. In this article, a walkthrough to creating a Workout Planner using MERN (Mongodb, Express, ReactJS, NodeJS) stack is explained. How to create own customized APIs using Mongoose for performing CRUD (Create, Read, Update and Delete) operations has been proposed along with an explanation of installation and setting up of the project.

Output Preview: Let us have a look at how the final output will loo like.

ezgifcom-video-to-gif-converter-(3)

Preview of the Website

Prerequisites

Approach to Create Workout Planner using MERN Stack

Functionalities:

  • User can register/login, the state of the user can be stored once the user logs in and logout is also possible.
  • A user can create custom routines and meals, and also view them.
  • A user can make an entry on a particular day and select the

Frontend:

  • Install necessary packages include fontawesome for icons, react-router-dom for routing etc.
  • Create the basic routing structure of the frontend application
  • Define page components that’ll be imported on every route and the internal components that form the atomic elements of the page.
  • Context APIs are used for state management i.e. whenever a user logs in the state gets stored for the required amount of time for every session. This helps to store information across components and their children.
  • A custom hook is created to fetch data from backend API.

Backend:

  • The model-view-controller architecture is employed for the backend.
  • Connect backend with the MongoDB Database using mongoose.
  • Define model schemas for Entry, Routine, Meal and User.
  • Create CRUD function in the controllers.
  • Create routes for each CRUD function.

Steps to create Workout Planner:

Step 1: Create a project folder using the following command.

mkdir workout planner
cd workout planner

Step 2: In your project folder create a folder by the name server and navigate to it.

mkdir server
cd server

Step 3: Install the required packages

npm install bcryptjs cors dotenv express cookie-parser jsonwebtoken mongodb mongoose morgan helmet nodemon

The updated Dependencies in package.json file of backend will look like:

"dependencies": {
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.4.4",
"express": "^4.18.2",
"cookie-parser": "^1.4.6",
"jsonwebtoken": "^9.0.2",
"mongodb": "^6.3.0",
"mongoose": "^8.1.3",
"morgan": "^1.10.0",
"helmet": "^7.1.0",
"nodemon": "^3.0.3"
}

Step 4: Create a .env file to store things you don’t want to show to others.

MONGO = [mongo database connection string can be found at on cloud.mongodb.com > Clusters > Connect button]

JWT = randomly generate code


Step 5: Create .gitignore file. Here we specify which files or folders need to be ignored while committing to git repositories. We generally add node modules and .env file here

node_modules
.env

Folder Structure(Backend):

sedr

Backend Folder Structure

Code Example: Create the required files as shown in folder structure and add the following codes.

Javascript
//controllers/auth.js

import User from "../models/User.js";
import bcrypt from "bcryptjs";
import { createError } from "../utils/error.js";
import jwt from "jsonwebtoken";

export const register = async (req, res, next) => {
    try {

        const em = await User.findOne({ email: req.body.email });
        if (em)
            return res.status(409).send({ message: "User with given email already exists" })


        const salt = bcrypt.genSaltSync(10);
        const hash = bcrypt.hashSync(req.body.password, salt);

        const newUser = new User({
            ...req.body,
            password: hash,
        });

        await newUser.save();
        res.status(200).send("User has been created.");
    } catch (err) {
        next(err);
    }
};


export const login = async (req, res, next) => {
    try {
        const user = await User.findOne({ username: req.body.username });
        if (!user) return next(createError(404, "User not found!"));

        const isPasswordCorrect = await bcrypt.compare(
            req.body.password,
            user.password
        );
        if (!isPasswordCorrect)
            return next(createError(400, "Wrong password or username!"));

        const token = jwt.sign(
            { id: user._id, isAdmin: user.isAdmin },
            process.env.JWT
        );

        const { password, isAdmin, ...otherDetails } = user._doc;
        res
            .cookie("access_token", token, {
                httpOnly: true,
            })
            .status(200)
            .json({ details: { ...otherDetails }, isAdmin });
    } catch (err) {
        next(err);
    }
};
Javascript
//controllers/user.js

import User from "../models/User.js";

export const updateUser = async (req, res, next) => {
    try {
        const updatedUser = await User.findByIdAndUpdate(
            req.params.id,
            { $set: req.body },
            { new: true }
        );
        res.status(200).json(updatedUser);
    } catch (err) {
        next(err);
    }
};

export const deleteUser = async (req, res, next) => {
    try {
        await User.findByIdAndDelete(req.params.id);
        res.status(200).json("User has been deleted.");
    } catch (err) {
        next(err);
    }
};

export const getUser = async (req, res, next) => {
    try {
        const user = await User.findById(req.params.id).populate('posts');

        res.status(200).json(user);
    } catch (err) {
        next(err);
    }
};

export const getUsers = async (req, res, next) => {
    try {
        const users = await User.find();
        res.status(200).json(users);
    } catch (err) {
        next(err);
    }
};
Javascript
//controllers/routine.js

import Routine from "../models/Routine.js"
import User from "../models/User.js"

export const createRoutine = async (req, res, next) => {

    const newRoutine = new Routine(req.body);
    try {
        const savedRoutine = await newRoutine.save();

        try {
            const user = await User.findById(savedRoutine.author);
            user.routines.push(savedRoutine._id);
            await user.save();
        }
        catch (err) {
            next(err)
        }
        res.status(200).json(savedRoutine);
    } catch (err) {
        next(err);
    }
};

export const updateRoutine = async (req, res, next) => {
    try {
        const routine = await Routine.findByIdAndUpdate(
            req.params.id,
            { $set: req.body },
            { new: true }
        );
        res.status(200).json(routine);
    } catch (err) {
        next(err);
    }
};

export const deleteRoutine = async (req, res, next) => {
    try {
        await Routine.findByIdAndDelete(req.params.id);
        res.status(200).json("the Routine has been deleted");
    } catch (err) {
        next(err);
    }
};


export const getRoutines = async (req, res, next) => {
    const userId = req.params.userId;

    try {
        const routines = await Routine.find({ author: userId });
        res.status(200).json(routines);
    } catch (err) {
        next(err)
    }
}
Javascript
//controllers/meal.js

import Meal from "../models/Meal.js"
import User from "../models/User.js"

export const createMeal = async (req, res, next) => {

    const newMeal = new Meal(req.body);
    try {
        const savedMeal = await newMeal.save();

        try {
            const user = await User.findById(savedMeal.author);
            user.meals.push(savedMeal._id);
            await user.save();
        }
        catch (err) {
            next(err)
        }
        res.status(200).json(savedMeal);
    } catch (err) {
        next(err);
    }
};

export const updateMeal = async (req, res, next) => {
    try {
        const meal = await Meal.findByIdAndUpdate(
            req.params.id,
            { $set: req.body },
            { new: true }
        );
        res.status(200).json(meal);
    } catch (err) {
        next(err);
    }
};

export const deleteMeal = async (req, res, next) => {
    try {
        await Meal.findByIdAndDelete(req.params.id);
        res.status(200).json("the Meal has been deleted");
    } catch (err) {
        next(err);
    }
};



export const getMeals = async (req, res, next) => {
    const userId = req.params.userId;

    try {
        const meals = await Meal.find({ author: userId });
        res.status(200).json(meals);
    } catch (err) {
        next(err)
    }
}
Javascript
//controllers/entry.js

import Entry from "../models/Entry.js"
import User from "../models/User.js"
import Routine from "../models/Routine.js"
import Meal from "../models/Meal.js"

export const createEntry = async (req, res, next) => {

    const newEntry = new Entry(req.body);
    try {
        const savedEntry = await newEntry.save();

        try {
            const user = await User.findById(savedEntry.author);
            user.entries.push(savedEntry._id);
            await user.save();
        }
        catch (err) {
            next(err)
        }
        res.status(200).json(savedEntry);
    } catch (err) {
        next(err);
    }
};

export const updateEntry = async (req, res, next) => {
    try {
        const entry = await Entry.findByIdAndUpdate(
            req.params.id,
            { $set: req.body },
            { new: true }
        );
        res.status(200).json(entry);
    } catch (err) {
        next(err);
    }
};

export const deleteEntry = async (req, res, next) => {
    try {
        await Entry.findByIdAndDelete(req.params.id);

        try {

            await User.findOneAndUpdate(
                { entries: req.params.id }, 
                { $pull: { entries: req.params.id } },
                { new: true }
            );
        }

        catch (err) {
            next(err)
        }

        res.status(200).json("the entry has been deleted");
    } catch (err) {
        next(err);
    }
};


export const getEntries = async (req, res, next) => {
    const userId = req.params.userId;
    try {
        const entries = await Entry.find({ author: userId })
            .populate('meals', 'name')
            .populate('routines', 'name')
        res.status(200).json(entries);
    } catch (err) {
        next(err)
    }
}

export const getMealsAndRoutines = async (req, res, next) => {
    const userId = req.params.id
    let userRoutines, userMeals;
    try {
        userRoutines = await Routine.find({ author: userId }).select('name _id').exec();
    }
    catch (err) {
        next(err)
    }
    try {
        userMeals = await Meal.find({ author: userId }).select('name _id').exec();
    }
    catch (error) {
        next(err)
    }
    const result = {
        routines: userRoutines,
        meals: userMeals
    }
    res.status(200).json(result);
}
Javascript
//models/User.js

import mongoose from "mongoose";

const UserSchema = new mongoose.Schema(
    {
        username: { type: String, required: true, unique: true },
        email: { type: String, required: true, unique: true },
        password: { type: String, required: true },
        profilePicture: { type: String, default: "" },
        routines: [
            {
                type: mongoose.Schema.Types.ObjectId,
                ref: 'Routine'
            }
        ],
        entries: [
            {
                type: mongoose.Schema.Types.ObjectId,
                ref: 'Entry'
            }
        ],
        meals: [
            {
                type: mongoose.Schema.Types.ObjectId,
                ref: 'Routine'
            }
        ],
    },
    {
        timestamps: true
    }
)

export default mongoose.model("User", UserSchema);
Javascript
//models/Routine.js

import mongoose from "mongoose";

const RoutineSchema = new mongoose.Schema(
    {
        name: { type: String, required: true },
        author: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'User', required: true
        },
        workout_type: { type: String, required: true },
        body_part: { type: String, required: true },
        link: { type: String }
    },
    {
        timestamps: true
    }
)

export default mongoose.model("Routine", RoutineSchema);
Javascript
//models/Meal.js

import mongoose from "mongoose";

const MealSchema = new mongoose.Schema(
    {
        name: { type: String, required: true },
        author: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'User', required: true
        },
        recipe: { type: String, default: "" },
        time: { type: Number, required: true },
        description: { type: String },
        category: { type: String, required: true }
    },
    {
        timestamps: true
    }
)

export default mongoose.model("Meal", MealSchema);
Javascript
//models/Entry.js

import mongoose from "mongoose";

const EntrySchema = new mongoose.Schema(
    {
        date: { type: Date, required: true },
        routines: [
            {
                type: mongoose.Schema.Types.ObjectId,
                ref: 'Routine'
            }
        ],
        meals: [
            {
                type: mongoose.Schema.Types.ObjectId,
                ref: 'Meal'
            }
        ],
        author: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'User',
            required: true
        },
    },
    {
        timestamps: true
    }
)

export default mongoose.model("Entry", EntrySchema);
Javascript
//routes/users.js

import express from "express";
import {
    deleteUser,
    getUser,
    getUsers,
    updateUser,
} from "../controllers/user.js";

const router = express.Router();

router.put("/:id", updateUser);
router.delete("/:id", deleteUser);
router.get("/:id", getUser);
router.get("/", getUsers);

export default router;
Javascript
//routes/routines.js

import express from "express";
import {
    createRoutine,
    deleteRoutine,
    getRoutines,
    updateRoutine,
} from "../controllers/routine.js";

const router = express.Router();

router.post("/", createRoutine);
router.put("/:id", updateRoutine);
router.delete("/:id", deleteRoutine);
router.get("/:userId", getRoutines);

export default router;
Javascript
//routes/meals.js

import express from "express";
import {
    createMeal,
    deleteMeal,
    getMeals,
    updateMeal,
} from "../controllers/meal.js";

const router = express.Router();

router.post("/", createMeal);
router.put("/:id", updateMeal);
router.delete("/:id", deleteMeal);
router.get("/:userId", getMeals);

export default router;
Javascript
//routes/entries.js

import express from "express";
import {
    createEntry,
    deleteEntry,
    getEntries,
    updateEntry,
    getMealsAndRoutines,
} from "../controllers/entry.js";

const router = express.Router();

router.post("/", createEntry);
router.put("/:id", updateEntry);
router.delete("/:id", deleteEntry);
router.get("/:userId", getEntries);
router.get("/fetchMealsAndRoutines/:id", getMealsAndRoutines)

export default router;
Javascript
//routes/auth.js

import express from "express";
import { login, register } from "../controllers/auth.js ";

const router = express.Router();

router.post("/register", register)
router.post("/login", login)

export default router;
Javascript
//utils/error.js

export const createError = (status, message) => {
    const err = new Error();
    err.status = status;
    err.message = message;
    return err;
};
Javascript
//index.js

import express from "express";
import dotenv from "dotenv";
import helmet from "helmet";
import morgan from "morgan";
import mongoose from "mongoose";
import userRoute from "./routes/users.js";
import authRoute from "./routes/auth.js";
import entryRoute from "./routes/entries.js";
import routineRoute from "./routes/routines.js";
import mealRoute from "./routes/meals.js";
import cookieParser from "cookie-parser";
import cors from "cors"

const app = express();
dotenv.config();

const PORT = process.env.PORT || 7700;

const connect = async () => {
    try {
        await mongoose.connect(process.env.MONGO);
        console.log("Connected to mongoDB.");
    } catch (error) {
        throw error;
    }
};

mongoose.connection.on("disconnected", () => {
    console.log("mongoDB disconnected!");
});

app.get('/', (req, res) => { res.send('Hello from Express!') });

app.use(cookieParser())
app.use(express.json());
app.use(helmet());

app.use(cors({
    origin: "http://localhost:3000",
    credentials: true
}))

app.use(morgan("common"));

app.use("/api/auth", authRoute);
app.use("/api/users", userRoute);
app.use("/api/entries", entryRoute);
app.use("/api/routines", routineRoute);
app.use("/api/meals", mealRoute);

app.listen(PORT, () => {
    console.log("Listening on port 2000");
    connect();
});

Step 6: To start the backend run the following command.

nodemon index.js

Testing the Functioning of Backend

Step 7: In order to check whether the API calls to various endpoints are working or not, Postman or Insomnia can be used for the testing.

In the following image, we can see that a create request has been successfully sent to Postman, as the status code indicates “200 OK” and the create document is printed in the console.

Screenshot-2024-02-21-080430

Create request for Meal sent to Postman, Document created successfully

Output of the User Created in MongoDB

Notice how the password is hashed. Also, the meal created in the above Postman example has been injected into the meals array of this particular user. We were able to achieve this by providing the ObjectId of the author.

Screenshot-2024-02-21-080409

User Document


Step 8: Create react application in your project folder using the following command and navigate to the folder.

npx create-react-app client
cd client

Step 9: Install additional packages

npm install axios react-router-dom @fortawesome/free-solid-svg-icons @fortawesome/react-fontawesome

Frontend Dependencies:

"dependencies": {
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.6.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Folder Structure:

Add-a-subheading(4)-(1)

Code Example: Create the required folders as seen on folder structure and add the following codes.

Javascript
//components/create/CreateEntry.jsx

import './popUp.css'

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faXmark } from '@fortawesome/free-solid-svg-icons'
import { useContext, useState } from 'react';
import axios from "axios"
import useFetch from '../../useFetch';
import { AuthContext } from '../../authContext';

const CreateEntry = ({ setOpen }) => {

    const { user } = useContext(AuthContext);
    const [info, setInfo] = useState({});
    const { data } = useFetch(`/entries/fetchMealsAndRoutines/${user._id}`)
    const handleChange = (e) => {
        setInfo((prev) => ({ ...prev, [e.target.id]: e.target.value }));
    }
    const handleClick = async (e) => {
        e.preventDefault();

        const newEntry = {
            ...info, author: user._id
        }
        try {
            await axios.post('http://localhost:2000/api/entries/', newEntry, {
                withCredentials: false
            })
            setOpen(false)
            console.log(newEntry)
        }
        catch (err) {
            console.log(err)
        }
    }

    const handleMultiSelectChange = (e) => {
        const { id, options } = e.target;
        const selectedOptions = Array.from(options)
            .filter(option => option.selected)
            .map(option => option.value);
        setInfo(prev => ({ ...prev, [id]: selectedOptions }));
    }

    return (
        <div className="modal">
            <div className="mContainer">

                <FontAwesomeIcon icon={faXmark} className="mClose" onClick={() => setOpen(false)} />

                <div className="mTitle">Create Entry</div>

                <form>
                    <input
                        className="formInput"
                        type="date"
                        onChange={handleChange}
                        id="date"
                    />

                    <div className="formInput" id='options'>
                        <label>Choose Meals</label>
                        <select
                            id="meals"
                            multiple
                            onChange={handleMultiSelectChange}
                        >
                            {data?.meals?.map((meal, index) => (
                                <option key={index} value={meal._id}>{meal.name}</option>
                            ))}
                        </select>
                    </div>

                    <div className="formInput" id='options'>
                        <label>Choose Routines</label>
                        <select
                            id="routines"
                            multiple
                            onChange={handleMultiSelectChange}
                        >
                            {data?.routines?.map((routine, index) => (
                                <option key={index} value={routine._id}>{routine.name}</option>
                            ))}
                        </select>
                    </div>
                </form>

                <button className="mButton" onClick={handleClick}>
                    Submit
                </button>
            </div>
        </div>
    )
}

export default CreateEntry
Javascript
//components/create/CreateMeal.jsx

import './popUp.css'

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faXmark } from '@fortawesome/free-solid-svg-icons'
import { useContext, useState } from 'react';
import axios from "axios"
import { AuthContext } from '../../authContext';
import { category } from '../../data';

const CreateMeal = ({ setOpen }) => {

    const { user } = useContext(AuthContext);
    const [info, setInfo] = useState({});
    const handleChange = (e) => {
        setInfo((prev) => ({ ...prev, [e.target.id]: e.target.value }));
    }

    const handleClick = async (e) => {
        e.preventDefault();

        const newMeal = {
            ...info, author: user._id
        }
        try {
            await axios.post("http://localhost:2000/api/meals", newMeal, {
                withCredentials: false
            })
            setOpen(false)
        }
        catch (err) {
            console.log(err)
        }
    }

    return (
        <div className="modal">
            <div className="mContainer">

                <FontAwesomeIcon icon={faXmark} className="mClose" onClick={() => setOpen(false)} />

                <div className="mTitle">Add Meal</div>

                <form>
                    <input
                        className="formInput"
                        type="text"
                        onChange={handleChange}
                        id="name"
                        placeholder='Enter your Meal name'
                    />
                    <textarea
                        name="Description"
                        id="description"
                        cols="30"
                        rows="10"
                        onChange={handleChange}
                        placeholder='Add meal details'>
                    </textarea>
                    <input
                        className="formInput"
                        type="text"
                        onChange={handleChange}
                        id="recipe"
                        placeholder='Add recipe links'
                    />
                    <input
                        className="formInput"
                        type="number"
                        onChange={handleChange}
                        id="time"
                        placeholder='Enter time in minutes'
                    />
                    <div className="formInput" id='options'>
                        <label>Choose Category</label>
                        <select id="category" onChange={handleChange}>
                            <option key={0} value="none">-</option>
                            {
                                category.map((c, index) => (

                                    <option key={index} value={c}>{c}</option>
                                ))
                            }
                        </select>
                    </div>
                </form>

                <button className="mButton" onClick={handleClick}>
                    Submit
                </button>
            </div>
        </div>
    )
}

export default CreateMeal
Javascript
//components/create/CreateRoutine.jsx

import './popUp.css'

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faXmark } from '@fortawesome/free-solid-svg-icons'
import { useContext, useState } from 'react';
import axios from "axios"
import { AuthContext } from '../../authContext.js';
import { WorkoutType, BodyPart } from "../../data.js"

const CreateRoutine = ({ setOpen }) => {

    const { user } = useContext(AuthContext);
    const [info, setInfo] = useState({});

    const handleChange = (e) => {
        setInfo((prev) => ({ ...prev, [e.target.id]: e.target.value }));
    }

    const handleClick = async (e) => {
        e.preventDefault();

        const newRoutine = {
            ...info, author: user._id
        }
        try {
            await axios.post("http://localhost:2000/api/routines", newRoutine, {
                withCredentials: false
            })
            setOpen(false)
        }
        catch (err) {
            console.log(err)
        }
    }

    return (
        <div className="modal">
            <div className="mContainer">

                <FontAwesomeIcon icon={faXmark} className="mClose" onClick={() => setOpen(false)} />

                <div className="mTitle">Create Routine</div>

                <form>
                    <input
                        className="formInput"
                        type="text"
                        onChange={handleChange}
                        id="name"
                        placeholder='Enter the Workout Name'
                    />
                    <input
                        className="formInput"
                        type="text"
                        onChange={handleChange}
                        id="link"
                        placeholder='Add workout link'
                    />

                    <div className="formInput" id='options'>
                        <label>Choose Workout Type</label>
                        <select id="workout_type" onChange={handleChange}>
                            <option key={0} value="none">-</option>
                            {
                                WorkoutType.map((w, index) => (

                                    <option key={index} value={w}>{w}</option>
                                ))
                            }
                        </select>
                    </div>

                    <div className="formInput" id='options'>
                        <label>Choose Body Part</label>
                        <select id="body_part" onChange={handleChange}>
                            <option key={0} value="none">-</option>
                            {
                                BodyPart.map((b, index) => (

                                    <option key={index} value={b}>{b}</option>
                                ))
                            }
                        </select>
                    </div>
                </form>

                <button className="mButton" onClick={handleClick}>
                    Submit
                </button>
            </div>
        </div>
    )
}

export default CreateRoutine
Javascript
// components/footer/Footer.jsx

import React from 'react'

const Footer = () => {
    return (
        <div className='footer' style={{
            'display': "flex",
            "alignItems": "center",
            "justifyContent": "center",
            "height": "100px",
            "backgroundColor": "#BE3144",
            "color": "white",
            "fontWeight": "800"
        }}>
            <p>ShapeSync</p>
        </div>
    )
}

export default Footer
Javascript
//components/homeComp/HomeComp.jsx

import React from "react";
import "./homeComp.css";
import { useState } from "react";
import { Link } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faPlus, faEye } from "@fortawesome/free-solid-svg-icons";
import CreateMeal from "../create/CreateMeal";
import CreateEntry from "../create/CreateEntry";
import CreateRoutine from "../create/CreateRoutine";

const HomeComp = ({ image, name, description, view }) => {
  const [openPopup, setOpenPopup] = useState(false);

  return (
    <div className="homeCompContainer">
      <div className="imgCont">
        <img src={image} alt="" />
      </div>
      <h2>{name}</h2>
      <p>{description}</p>
      {/* create */}
      <div className="buttons">
        <div className="createButton">
          <button onClick={() => setOpenPopup(true)}>
            <FontAwesomeIcon icon={faPlus} />
          </button>
          <p>Add</p>
        </div>
        {/* view */}
        <div className="viewButton">
          <Link to={view}>
            <button>
              <FontAwesomeIcon icon={faEye} />
            </button>
          </Link>
          <p>View</p>
        </div>
      </div>
      {openPopup && name === "Meals" && <CreateMeal setOpen={setOpenPopup} />}
      {openPopup && name === "Entries" && (
        <CreateEntry setOpen={setOpenPopup} />
      )}
      {openPopup && name === "Routines" && (
        <CreateRoutine setOpen={setOpenPopup} />
      )}
    </div>
  );
};

export default HomeComp;
Javascript
//components/Navbar/Navbar.jsx

import './navbar.css'
import { useState, useContext } from 'react';
import { faBars } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, useNavigate } from "react-router-dom"
import { AuthContext } from "../../authContext"


const Navbar = () => {

    const navigate = useNavigate()

    const { user, dispatch } = useContext(AuthContext)
    const handleClick = async (e) => {
        e.preventDefault();
        dispatch({ type: "LOGOUT" });
        navigate("/")
    }



    return (
        <div className='navContainer'>
            <Link to="/home">
                <p className='navLogo'>ShapeSync</p>
            </Link>

            <input type="checkbox" id='menu-bar' />
            <label htmlFor="menu-bar">
                <FontAwesomeIcon icon={faBars} className="icon" /></label>
            <nav className='navbar'>
                <ul>
                    <Link to="/routines">
                        <li><p>Routine</p></li>
                    </Link>
                    <Link to="/meals">
                        <li><p>Meal</p></li>
                    </Link>
                    <Link to="/entries">
                        <li><p>Entries</p></li>
                    </Link>
                    {user ? (<>

                        <Link to={`/user/${user._id}`}>
                            <li onClick={handleClick} style={{ cursor: "pointer" }}>
                            <p>Logout</p></li>
                            <li><div className="profilePicture">
                                <img src={user.profilePicture || 
                                "https://i.ibb.co/MBtjqXQ/no-avatar.gif"} alt="" />
                            </div></li>
                            <li id="usernamename"><p>{user.username}</p></li>
                        </Link>
                    </>
                    )
                        :
                        (
                            <>
                                <Link to="/register">
                                    <li><p>Register</p></li>
                                </Link>
                                <Link to="/login">
                                    <li><p>Login</p></li>
                                </Link>
                            </>
                        )}
                </ul>
            </nav>
        </div >
    )
}

export default Navbar
Javascript
//App.js

import { BrowserRouter, Routes, Route } from "react-router-dom"
import Landing from "./pages/Landing/Landing";
import Login from "./pages/Login/Login";
import Register from "./pages/Register/Register";
import Entries from "./pages/Entry/Entries";
import Routines from "./pages/Routine/Routines"
import { useContext } from "react";
import { AuthContext } from "./authContext";
import Home from "./pages/home/Home";
import Meal from "./pages/Meal/Meal";


function App() {
    const { user } = useContext(AuthContext);

    const ProtectedRoute = ({ children }) => {
        if (!user) {
            return <Login title="Login to Create" />;
        } else {
            return children;
        }
    };

    return (
        <BrowserRouter>
            <Routes>
                <Route path="/" element={<Landing />} />
                <Route path="/home" element={<Home />} />
                <Route path="/login" element={<Login />} />
                <Route path="/register" element={<Register />} />
                <Route path="/entries" element={<ProtectedRoute><Entries /></ProtectedRoute>} />
                <Route path="/meals" element={<ProtectedRoute><Meal /></ProtectedRoute>} />
                <Route path="/routines" element={<ProtectedRoute><Routines /></ProtectedRoute>} />
            </Routes>
        </BrowserRouter>
    );
}

export default App;
Javascript
//authContext.js

import { createContext, useReducer, useEffect } from "react"

const INITIAL_STATE = {
    user: JSON.parse(localStorage.getItem("user")) || null,
    loading: false,
    error: null,
};


export const AuthContext = createContext(INITIAL_STATE)

const AuthReducer = (state, action) => {
    switch (action.type) {
        case "LOGIN_START":
            return {
                user: null,
                loading: true,
                error: null
            };

        case "LOGIN_SUCCESS":
            return {
                user: action.payload,
                loading: false,
                error: null
            };

        case "LOGIN_FAILURE":
            return {
                user: null,
                loading: false,
                error: action.payload
            };

        case "LOGOUT":
            return {
                user: null,
                loading: false,
                error: null
            };
        default:
            return state;
    }
}

export const AuthContextProvider = ({ children }) => {
    const [state, dispatch] = useReducer(AuthReducer, INITIAL_STATE)

    useEffect(() => {
        localStorage.setItem("user", JSON.stringify(state.user))
    }, [state.user])


    return (
        <AuthContext.Provider
            value={{
                user: state.user,
                loading: state.loading,
                error: state.error,
                dispatch
            }}
        >
            {children}
        </AuthContext.Provider>
    )
}
Javascript
//data.js

export const WorkoutType = [
    "Cardio", "HIIT", "Strength Training", "Yoga", "Zumba"
]

export const BodyPart = [
    'Chest', 
    'Back',  
    'Arms',  
    'Shoulders',  
    'Legs',
    'Whole',
    'Glutes',
    'Abs'
]

export const category = [
    'Appetizer & Snacks',
    'Baking',
    'Grill',
    'Breakfast & Brunch',
    'Salads',
    'Drinks',
    'Junk',
    'Main Course',
]
Javascript
//index.js

import React from 'react';
import "./style.css"
import ReactDOM from 'react-dom/client';
import { AuthContextProvider } from './authContext';


import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <AuthContextProvider>
        <React.StrictMode>
            <App />
        </React.StrictMode>
    </AuthContextProvider>
);
Javascript
//useFetch.js

import { useEffect, useState } from "react";
import axios from "axios";

const useFetch = (url) => {
    const [data, setData] = useState([]);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(false);

    useEffect(() => {
        const fetchData = async () => {
            setLoading(true);
            try {

                const res = await axios.get(url)

                setData(res.data);
            } catch (err) {
                setError(err);
            }
            setLoading(false);
        };
        fetchData();
    }, [url]);

    const reFetch = async () => {
        setLoading(true);
        try {
            const res = await axios.get(url)

            setData(res.data);
        } catch (err) {
            setError(err);
        }
        setLoading(false);
    };

    return { data, loading, error, reFetch };
};

export default useFetch;
Javascript
//pages/Entry/Entries.jsx

import React, { useContext } from 'react'
import useFetch from '../../useFetch'
import Navbar from "../../components/Navbar/Navbar"
import Footer from "../../components/Footer/Footer"
import "./entry.css"
import { AuthContext } from '../../authContext'

const Entries = () => {

    const { user } = useContext(AuthContext)


    const { data } = useFetch(`/entries/${user._id}`)

    function formatDate(dateString) {

        const date = new Date(dateString);

        const day = date.getDate().toString().padStart(2, '0');
        const month = (date.getMonth() + 1).toString().padStart(2, '0');
        const year = date.getFullYear();


        const formattedDate = `${day}-${month}-${year}`;

        return formattedDate;
    }

    return (
        <div className='entry'>
            <Navbar />

            <div className="entriesContainer">
                {
                    data?.map((d, index) => (
                        <div className="entryItem" key={index}>
                            <h1>{formatDate(d.date)}</h1>
                            <h2>Meals taken</h2>
                            <div className="mealsContainer">
                                {d?.meals?.map((m, i) => (
                                    <div className="mealItem" key={i}>{m.name}</div>
                                ))}
                            </div>
                            <h2>Exercise done</h2>
                            <div className="routinesContainer">
                                {d?.routines?.map((r, j) => (
                                    <div className="routineItem" key={j}>{r.name}</div>
                                ))}
                            </div>
                        </div>
                    ))
                }
            </div>
            <Footer />
        </div>
    )
}

export default Entries
Javascript
// pages/home/Home.jsx

import React from 'react'
import "./home.css"
import Navbar from "../../components/Navbar/Navbar"
import Footer from "../../components/Footer/Footer"
import HomeComp from '../../components/homeComp/HomeComp'


const Home = () => {
    return (
        <div className='home'>
            <Navbar />
            <div className="banner">
                <h1>Welcome to ShapeSync</h1>
                <p>The one stop solution for your fitness journey</p>
            </div>
            <div className="mainContainer">
                <HomeComp
                    image="https://media.geeksforgeeks.org/wp-content/uploads/20240308220039/planner.png"
                    name="Entries"
                    description="Keep track of your daily progress"
                    view="/entries"
                />
                <HomeComp
                    image="https://media.geeksforgeeks.org/wp-content/uploads/20240308220039/routine.png"
                    name="Routines"
                    description="Add personalized routines"
                    view="/routines"
                />
                <HomeComp
                    image="https://media.geeksforgeeks.org/wp-content/uploads/20240308220038/meal.png"
                    name="Meals"
                    description="Add personalized meals"
                    view="/meals"
                />

            </div>
            <Footer />

        </div>
    )
}

export default Home
Javascript
//pages/Landing/Landing.jsx

import React, { useContext } from 'react'
import "./landing.css"
import { AuthContext } from '../../authContext'
import { Link } from "react-router-dom"

const Landing = () => {

    const { user } = useContext(AuthContext)

    return (
        <div className='landing'>
            <div className="header">
            </div>
            <div className="upper-layer">
                <h1>Welcome to <span className='brand-name'>ShapeSync</span></h1>
                <Link to={user ? '/home' : '/login'}>
                    <button className='btn-get-started'>Get Started</button>
                </Link>
            </div>

        </div>
    )
}

export default Landing
Javascript
//pages/Login/Login.jsx

import React from "react";
import Footer from "../../components/Footer/Footer";
import Navbar from "../../components/Navbar/Navbar";
import "./login.css";
import axios from "axios";
import { useContext, useState } from "react";
import { useNavigate, Link } from "react-router-dom";
import { AuthContext } from "../../authContext";

function Login() {
    const [credentials, setCredentials] = useState({
        username: undefined,
        password: undefined,
    });

    const { dispatch } = useContext(AuthContext);
    const navigate = useNavigate();

    const handleChange = (e) => {
        setCredentials((prev) => ({ ...prev, [e.target.id]: e.target.value }));
    };

    const handleClick = async (e) => {
        e.preventDefault();
        dispatch({ type: "LOGIN_START" });
        try {
            const res = await axios.post("http://localhost:2000/api/auth/login", credentials);
            dispatch({ type: "LOGIN_SUCCESS", payload: res.data.details });
            navigate('/home');
        } catch (err) {
            if (err.response && err.response.data) {
                dispatch({ type: "LOGIN_FAILURE", payload: err.response.data });
            } else {
                dispatch({ type: "LOGIN_FAILURE", payload: "An error occurred while logging in" });
            }
        }
    };


    return (
        <div className="login">
            <Navbar />
            <div className="loginCard">
                <div className="center">
                    <h1>Welcome Back!</h1>
                    <form>
                        <div className="txt_field">
                            <input
                                type="text"
                                placeholder="username"
                                id="username"
                                onChange={handleChange}
                                className="lInput"
                            />
                        </div>
                        <div className="txt_field">
                            <input
                                type="password"
                                placeholder="password"
                                id="password"
                                onChange={handleChange}
                                className="lInput"
                            />
                        </div>
                        <div className="login_button">
                            <button className="button" onClick={handleClick}>
                                Login
                            </button>
                        </div>
                        <div className="signup_link">
                            <p>
                                Not registered? <Link to="/register">Register</Link>
                            </p>
                        </div>
                    </form>

                </div>
            </div>
            <Footer />
        </div>
    );
}

export default Login;
Javascript
//pages/Meal/Meal.jsx

import React, { useContext } from 'react'
import Navbar from "../../components/Navbar/Navbar"
import Footer from "../../components/Footer/Footer";
import useFetch from '../../useFetch';
import { AuthContext } from '../../authContext'
import "./meal.css"
import { Link } from 'react-router-dom';

const Meal = () => {
    const { user } = useContext(AuthContext)
    const { data } = useFetch(`/meals/${user._id}`)

    return (
        <div className='mealsView'>
            <Navbar />

            <div className="mealsViewContainer">
                {
                    data?.map((m, index) => (
                        <div className="mealViewItem" key={index}>
                            <div className="mealDetails">
                                <div className="mealName">{m.name}</div>
                                <div className="mealDesc">{m.description}</div>
                                <div className="mealTime">{m.time} minutes</div>
                                <div className="mealCat">{m.category}</div>
                            </div>
                            {m.recipe && <Link to={m.recipe} 
                                style={{ textDecoration: "none", color: "black" }}>
                                <div className="mealLink">Watch Recipe Video</div>
                            </Link>}
                        </div>
                    ))
                }
            </div>

            <Footer />
        </div>
    )
}

export default Meal
Javascript
//pages/Register/Register.jsx

import React from "react";
import Navbar from "../../components/Navbar/Navbar";
import Footer from "../../components/Footer/Footer";
import "./register.css";
import { Link } from "react-router-dom";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";

function Register() {
    const navigate = useNavigate();

    const [file, setFile] = useState("");
    const [info, setInfo] = useState({});

    const handleChange = (e) => {
        setInfo((prev) => ({ ...prev, [e.target.id]: e.target.value }));
    };

    const handleClick = async (e) => {
        e.preventDefault();

        if (file) {
            const data = new FormData();

            data.append("file", file);
            data.append("upload_preset", "upload");


            try {
                const uploadRes = await axios.post(
                    "your api cloudnary api link/image/upload",
                    data, { withcredentials: false }
                );

                const { url } = uploadRes.data;

                const newUser = {
                    ...info,
                    profilePicture: url,
                };

                await axios.post("/auth/register", newUser, { withcredentials: false })

                navigate("/login");
            } catch (err) {
                console.log(err);
            }
        } else {
            try {
                await axios.post("/auth/register", info, { withcredentials: false })

                navigate("/login");
            } catch (err) {
                console.log(err)
            }
        }
    };



    return (
        <div className="register">
            <Navbar />
            <div className="registerCard">
                <div className="center">
                    <h1>Join Us</h1>

                    <form>
                        <div className="image">
                            <img
                                src={
                                    file
                                        ? URL.createObjectURL(file)
                                        : "https://icon-library.com/images/no-image-icon
                                        /no-image-icon-0.jpg"
                                }
                                alt=""
                                height="100px"
                            />

                            <div className="txt_field_img">
                                <label htmlFor="file">
                                    Image
                                    {/* <FontAwesomeIcon className="icon" 
                                    icon={faPlusCircle} /> */}
                                </label>
                                <input
                                    type="file"
                                    id="file"
                                    onChange={(e) => setFile(e.target.files[0])}
                                    style={{ display: "none" }}
                                />
                            </div>
                        </div>

                        <div className="formInput">


                            <div className="txt_field">
                                <input
                                    type="text"
                                    placeholder="username"
                                    name="username"
                                    onChange={handleChange}
                                    id="username"
                                    required
                                />
                            </div>
                            <div className="txt_field">
                                <input
                                    type="email"
                                    placeholder="email"
                                    name="email"
                                    onChange={handleChange}
                                    id="email"
                                    required
                                />
                            </div>
                            <div className="txt_field">
                                <input
                                    type="password"
                                    placeholder="password"
                                    name="password"
                                    onChange={handleChange}
                                    id="password"
                                    //   value={data.password}
                                    required
                                />
                            </div>
                        </div>
                        <div className="login_button">
                            <button className="button" onClick={handleClick}>
                                Register
                            </button>
                        </div>
                        <div className="signup_link">
                            <p>
                                Already Registered? <Link to="/login">Login</Link>
                            </p>
                        </div>
                    </form>
                </div>
            </div>

            <Footer />
        </div>
    );
}

export default Register;
Javascript
//pages/Routine/Routines.jsx

import React, { useContext } from 'react'
import Navbar from "../../components/Navbar/Navbar"
import Footer from "../../components/Footer/Footer";
import useFetch from '../../useFetch';
import { AuthContext } from '../../authContext'
import './routine.css'
import { Link } from 'react-router-dom';

const Routines = () => {
    const { user } = useContext(AuthContext)
    const { data } = useFetch(`/routines/${user._id}`)

    return (
        <div className='routinesView'>
            <Navbar />
            <div className="routinesViewContainer">
                {
                    data?.map((r, index) => (
                        <div className="routineViewItem" key={index}>

                            <div className="routineDetails">
                                <div className="routineName">{r.name}</div>
                                <div className="routineType">{r.workout_type}</div>
                                <div className="routinePart">{r.body_part}</div>
                            </div>
                            {r.link && <Link to={r.link} style={{ textDecoration: "none", color: "black" }}>
                                <div className="routineLink">Watch Workout Video</div>
                            </Link>}
                        </div>
                    ))
                }
            </div>
            <Footer />
        </div>
    )
}

export default Routines


Now add the CSS files to style your application.

CSS
/* components/create/popUp.css */

.modal {
    width: 100vw;
    height: 100vh;
    background-color: rgba(0, 0, 0, 0.418);
    position: fixed;
    top: 0;
    left: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    z-index: 1000;
}

.mContainer {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    background-color: white;
    padding: 20px;
    height: fit-content;
    position: relative;
    width: 400px;
}


.mClose {
    position: absolute;
    top: 0;
    right: 0;
    cursor: pointer;
    padding: 5px;
    transition: all 0.3s ease-in-out;
    background-color: black;
    color: white;
    margin: 5px 5px 0 0;
    border-radius: 50%;
}

.mClose:hover {
    background-color: var(--red);
}

.mTitle {
    font-weight: 500;
    text-transform: capitalize;
    font-size: 1.5rem;
    padding: 10px 0;
}

.mContainer .formInput,
#description {
    font-size: 1.0rem;
    padding: 10px;
    margin: 15px;
    font-family: "Dosis", sans-serif;
}

.mButton {
    border: none;
    padding: 10px 20px;
    background-color: var(--dark-orange);
    color: white;
    font-weight: bold;
    cursor: pointer;
    border-radius: 5px;
    width: 200px;
    margin-top: 20px;
    transition: all 0.2s ease-in-out;
}

.mButton:hover {
    background-color: var(--orange);
}

#options {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    font-size: 1.2rem;
}

#options label {
    margin-bottom: 10px;
}

#options select {
    padding: 10px;
}
CSS
/* components/homeComp/homeComp.css */

.homeCompContainer {
    height: fit-content;
    width: 300px;
    background-color: rgba(255, 228, 196, 0.523);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 20px;
    gap: 10px;
    border-radius: 50px;
}

.homeCompContainer .imgCont {
    height: 50px;
    width: 50px;
    background-color: white;
    border-radius: 50%;
}

.homeCompContainer .imgCont img {
    height: 50px;
    width: 50px;
    object-fit: cover;
}

.home .buttons {
    display: flex;
    gap: 20px;
}

.home .createButton {
    display: flex;
    gap: 10px;
    align-items: center;
    justify-content: center;
    color: var(--dark-red);
    font-weight: 700;
    border: 2px solid var(--cream);
    padding: 10px;
    border-radius: 20px;
}

.home .createButton button {
    background-color: white;
    outline: none;
    border: none;
    padding: 8px 10px;
    cursor: pointer;
    border-radius: 50%;
}

.home .createButton button:hover {
    transform: translateY(-2px);
}

.home .viewButton {
    display: flex;
    gap: 10px;
    align-items: center;
    justify-content: center;
    color: var(--dark-red);
    font-weight: 700;
    border: 2px solid var(--cream);
    padding: 10px;
    border-radius: 20px;
}

.home .viewButton button {
    background-color: white;
    outline: none;
    border: none;
    padding: 8px 10px;
    cursor: pointer;
    border-radius: 50%;
}

.home .viewButton button:hover {
    transform: translateY(-2px);
}
CSS
/* components/Navbar/navbar.css */

* {
    margin: 0;
    padding: 0;
    text-decoration: none;
}

.navContainer {
    overflow: hidden;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    background-color: var(--dark-red);
    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
    padding: 0px 7%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    z-index: 100;
}


.navLogo {
    color: white;
    font-family: "Rubik Doodle Shadow", system-ui;
    font-weight: 900;
    font-size: 1.5rem;
    font-style: italic;
}

.navbar ul {
    list-style: none;
}

.navbar ul li {
    position: relative;
    float: left;
}

.profilePicture {
    height: 40px;
    width: 40px;
}

.profilePicture img {
    margin-top: 10px;
    height: 40px;
    width: 40px;
    border-radius: 50%;
    object-fit: cover;
}

#usernamename {
    display: none;
}

.navbar ul li p {
    font-size: 1rem;
    padding: 20px;
    color: white;
    display: block;
    transition: all 1s;
}

.navbar ul li p:hover {
    transform: translateY(-1px);
    border-bottom: solid 2px white;
}

#menu-bar {
    display: none;
}

.navContainer label {
    font-size: 1.5rem;
    color: white;
    cursor: pointer;
    display: none;
}

@media (max-width:800px) {
    .navContainer {
        height: 70px;
    }

    .navContainer label {
        display: initial;
    }

    .navContainer .navbar {
        position: fixed;
        top: 70px;
        left: -100%;
        text-align: center;
        background: white;
        border-top: 1px solid rgba(0, 0, 0, 0.1);
        display: block;
        transition: all 0.3s ease;
        width: 100%;
    }

    .profilePicture {
        display: none;
    }

    #usernamename {
        font-weight: bolder;
        display: block;
    }

    .navbar ul li p {
        color: black;
    }

    .navbar ul li p:hover {
        transform: translateY(-1px);

        border-bottom: none;
    }

    .navbar ul li {
        width: 100%;
    }

    #menu-bar:checked~.navbar {
        left: 0;
    }
}
CSS
/* style.css */

body {
    margin: 0;
    padding: 0;
    font-family: "Dosis", sans-serif;
}

:root {
    --black: #22092C;
    --dark-orange: #F05941;
    --dark-red: #872341;
    --red: #BE3144;
    --orange: #FFA33C;
    --yellow: #FFFB73;
    --cream: #FECDA6;
}
CSS
/* pages/Entry/entry.css */

.entry {
    margin: 100px 0;
}

.entry .entriesContainer {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 50px;
    margin-bottom: 50px;
    flex-wrap: wrap;
}

.entriesContainer .entryItem {
    height: 200px;
    text-align: center;
    width: 500px;
    padding: 30px;
    border-radius: 20px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 10px;
    background-color: rgba(255, 228, 196, 0.523);
}

.entryItem h1 {
    background-color: var(--dark-red);
    color: white;
    border-radius: 10px;
    padding: 5px;
}

.entryItem .mealsContainer {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

.entryItem .mealsContainer .mealItem {
    background-color: var(--cream);
    padding: 5px;
    font-weight: bold;
    border-radius: 10px;
}

.entryItem .routinesContainer {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.entryItem .routinesContainer .routineItem {
    background-color: var(--cream);
    padding: 5px;
    font-weight: bold;
    border-radius: 10px;
}
CSS
/* pages/home/home.css */

.home .banner {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    margin-top: 100px;
    gap: 50px;
    height: 300px;
}

.home .banner h1 {
    font-size: 2.5rem;
}

.home .banner p {
    font-size: 1.5rem;
}


.home .mainContainer {
    margin: 50px 0;
    display: flex;
    flex-flow: wrap;
    gap: 20px;
    justify-content: center;
    align-items: center;
}
CSS
/* pages/Landing/landing.css */

.landing {
    position: relative;
    background-color: black;
}

.landing .header {
    height: 100vh;
    width: 100vw;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: rgb(236, 96, 89);
    background: linear-gradient(310deg, rgba(236, 96, 89, 1) 0%,
            rgba(255, 218, 126, 1) 28%, rgba(255, 94, 74, 1) 100%);
}


.btn-get-started {
    background-color: var(--dark-red);
    border: 1px solid white;
    outline: none;
    color: white;
    padding: 15px 25px;
    font-family: "Dosis", sans-serif;
    cursor: pointer;
    font-size: 1.5rem;
    transition: all 0.3s ease;
}

.btn-get-started:hover {
    font-size: 1.6rem;
}

.upper-layer {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    width: 100%;
    flex-direction: column;
    gap: 100px;
    align-items: center;
    justify-content: center;
}

.upper-layer h1 {
    background-color: rgba(160, 46, 46, 0.448);
    color: azure;
    width: 50%;
    font-weight: 500;
    text-align: center;
    padding: 50px 0;
}

.upper-layer h1 span {
    color: white;
    font-family: "Rubik Doodle Shadow", system-ui;
    font-style: italic;
    font-weight: 900;
    padding: 5px;
}
CSS
/* pages/Login/login.css */

body,
html {
    overflow-x: hidden;
}

.loginCard {
    background-size: cover;
    background-repeat: no-repeat;
    height: 100vh;
    overflow: hidden;
}

.center {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 400px;
    background-color: #fecda630;
    border-radius: 10px;
    padding-top: 20px;
}

.center h1 {
    font-size: 1.2rem;
    text-align: center;
    padding: 0 0 20px 0;
    border-bottom: 1px solid silver;
}

.center form {
    padding: 0 40px;
    box-sizing: border-box;
}

form .txt_field {
    position: relative;
    border-bottom: 2px solid #adadad;
    margin: 30px 0;
}

.txt_field {
    width: 100%;
    padding: 0 5px;
    height: 40px;
    font-size: 16px;
    border: none;
    background: none;
    outline: none;
}

.txt_field input {
    width: 100%;
    padding: 0 5px;
    height: 40px;
    font-size: 16px;
    border: none;
    background: none;
    outline: none;
}

.login_button .button {
    width: 100%;
    height: 50px;
    border: none;
    background: transparent;
    border-radius: 25px;
    font-size: 18px;
    color: black;
    font-weight: 700;
    cursor: pointer;
    outline: none;
}

.login_button {
    width: 100%;
    height: 50px;
    border: none;
    background: var(--red);
    border-radius: 25px;
    font-size: 18px;
    color: white;
    font-weight: 700;
    cursor: pointer;
    outline: none;
}

.signup_link {
    margin: 30px 0;
    text-align: center;
    font-size: 16px;
    color: #666666;
}

.signup_link a {
    color: var(--orange);
    text-decoration: none;
}

.signup_link a:hover {
    text-decoration: underline;
}

@media screen and (max-width: 600px) {
    .loginCard .center {
        width: 300px;
    }
}
CSS
/* pages/Meal/meal.css */

.mealsView .mealsViewContainer {
    margin: 100px 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 30px;
    text-align: center;
}

.mealsView .mealsViewContainer .mealViewItem {
    border: 5px solid var(--red);
    position: relative;
    height: 300px;
    width: 300px;
    display: flex;
    flex-direction: column;
}



.mealsView .mealsViewContainer .mealDetails {
    background-color: white;
    border-radius: 10px;
    padding: 5px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    position: absolute;
    top: 60%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.mealsViewContainer .mealDetails .mealName {
    font-size: 1.3rem;
    font-weight: bold;
}

.mealsViewContainer .mealDetails .mealTime {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--dark-red);
}

.mealsViewContainer .mealDetails .mealCat {
    background-color: rgba(255, 228, 196, 0.523);
    border-radius: 10px;
    padding: 5px;
    font-weight: 700;
}

.mealsViewContainer .mealLink {
    font-size: 1.2rem;
    font-weight: 500;
    color: white;
    padding: 5px 0;
    background-color: var(--red);
    cursor: pointer;
}

.mealsViewContainer .mealLink:hover {
    background-color: var(--dark-red);
}
CSS
/* pages/Register/register.css */

body,
html {
    overflow-x: hidden;
}

.registerCard {
    background-size: cover;
    background-repeat: no-repeat;
    height: 1000px;
    overflow: hidden;
    position: relative;
}

.registerCard .center {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 400px;
    background-color: #fecda630;
    border-radius: 10px;
}

.center h1 {
    font-size: 1.2rem;
    text-align: center;
    padding: 0 0 20px 0;
    border-bottom: 1px solid silver;
}

.center form {
    padding: 0 40px;
    box-sizing: border-box;
}

form .txt_field {
    position: relative;
    border-bottom: 2px solid #adadad;
    margin: 30px 0;
}

form .txt_field_img {
    position: relative;
    margin-top: 10px;
}

.txt_field {
    width: 100%;
    padding: 0 5px;
    height: 40px;
    font-size: 16px;
    border: none;
    background: none;
    outline: none;
}

.txt_field input {
    width: 100%;
    padding: 0 5px;
    height: 40px;
    font-size: 16px;
    border: none;
    background: none;
    outline: none;
}

.registerCard form .image {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    margin-top: 20px;
}

.register input {
    width: 100%;
    height: 50px;
    border: none;
    background: transparent;
    border-radius: 25px;
    font-size: 16px;
    color: black;
    outline: none;
}

.login_button .button {
    width: 100%;
    height: 50px;
    border: none;
    background: transparent;
    border-radius: 25px;
    font-size: 18px;
    color: white;
    font-weight: 700;
    cursor: pointer;
    outline: none;
}

.login_button {
    width: 100%;
    height: 50px;
    border: none;
    background: var(--red);
    border-radius: 25px;
    font-size: 18px;
    color: white;
    font-weight: 700;
    cursor: pointer;
    outline: none;
}

.signup_link {
    margin: 30px 0;
    text-align: center;
    font-size: 16px;
    color: #666666;
}

.signup_link a {
    color: var(--orange);
    text-decoration: none;
}

.signup_link a:hover {
    text-decoration: underline;
}

@media screen and (max-width: 500px) {
    .registerCard .center {
        width: 300px;
        margin: 0;
    }
}
CSS
/* pages/Routine/routine.css */

.routinesView .routinesViewContainer {
    margin: 100px 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 30px;
    text-align: center;
}

.routinesView .routinesViewContainer .routineViewItem {
    border: 5px solid var(--red);
    position: relative;
    display: flex;
    flex-direction: column;
    width: 500px;
    background-color: rgb(45, 4, 4);
    height: 300px;
}


.routinesView .routinesViewContainer .routineDetails {
    background-color: rgba(255, 255, 255, 0.392);
    border-radius: 10px;
    color: white;
    padding: 10px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.routinesViewContainer .routineDetails .routineName {
    font-size: 1.3rem;
    font-weight: bold;
}

.routinesViewContainer .routineDetails .routineType {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--cream);
}

.routinesViewContainer .routineDetails .routinePart {
    background-color: var(--red);
    border-radius: 10px;
    padding: 10px;
    font-weight: 700;
}

.routinesViewContainer .routineLink {
    font-size: 1.2rem;
    font-weight: 700;
    color: white;
    background-color: var(--red);
    padding: 5px 0;
    cursor: pointer;
}

.routinesViewContainer .routineLink:hover {
    background-color: var(--dark-red);
}


Step 10: To start the client, run the following commands in the terminal

npm start

Output: The following gif shows the final website, where user can logic, register as manage their daily workout and meal plans.

ReactApp-GoogleChrome2024-03-0822-30-07-ezgifcom-video-to-gif-converter

Workout Planner using MERN Stack



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads