Open In App

Social Fitness App using MERN Stack

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

Creating a Social Fitness App is a great opportunity for anyone who wants to understand full-stack development. In this article, we’ll make a Social Fitness App from scratch using the MERN(MongoDB, Express.js, React, Node.js) stack. This project will help navigate backend development, and teach you the process of integrating frontend functionality with backend infrastructure. It will also showcase how to leverage MongoDB for storing user profiles, workout data, and interaction.

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

Screenshot-2024-03-06-125147

Output

Prerequisites:

Approach to Create Social Fitness App:

  • Define a functional component named App in ‘App.js’.
  • Make a list of necessary dependencies and component and import them.
  • Define Home and WorkoutPage components and wrap them inside in the App components to provide access to shared context data
  • Use React Router to navigate between different pages.
  • Use Axios to fetch data from backend server.
  • Establish connections to the MongoDB database from the backend server using Mongoose or MongoDB native drivers.

Steps to Create Server:

Step 1: Create a new directory named backend.

mkdir backend
cd backend

Step 2: Create a server using the following command in your terminal.

npm init -y

Step 3: Install the necessary package in your server using the following command.

npm install express mongoose mongodb dotenv cors

Step 4: Store Environment Variables

PORT=3001
MONGODB_URI=mongodb://localhost:27017/social_fitness_app
JWT_SECRET=your_secret_key

Project Structure:

Screenshot-2024-02-26-151217

Backend Project Structure

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

 "dependencies": {
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.18.2",
"mongodb": "^6.3.0",
"mongoose": "^8.2.0"
}

Step 5: Create a file ‘server.js’ and set up the server.

Javascript




// server.js
 
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const PORT = process.env.PORT || 5000;
const cors = require('cors');
 
app.use(express.json());
app.use(cors()); // Use the cors middleware
 
// Define Mongoose schemas (same as before)
const workoutSchema = new mongoose.Schema({
    name: String,
    description: String,
    duration: Number, // Duration in minutes
});
 
const workoutPlanSchema = new mongoose.Schema({
    name: String,
    description: String,
    imageUrl: String,
    workouts: [workoutSchema], // Array of workouts
});
 
// Define mock data
const workoutPlans = [
    {
        id: 1,
        name: 'Cardio Workout',
        description: 'A high-intensity cardio workout',
        workouts: [
            {
                name: 'Jumping Jacks',
                description: 'Start with 3 sets of 20 reps',
                duration: 5
            },
            {
                name: 'Running',
                description: 'Run for 30 minutes at a moderate pace',
                duration: 30
            },
            {
                name: 'Cycling',
                description: 'Cycle for 45 minutes at a steady pace',
                duration: 45
            },
            {
                name: 'Jump Rope',
                description: 'Jump rope for 15 minutes with intervals',
                duration: 15
            },
            {
                name: 'Swimming',
                description: 'Swim for 1 hour focusing on different strokes',
                duration: 60
            },
            {
                name: 'HIIT',
                description: 'High-Intensity Interval Training for 20 minutes',
                duration: 20
            },
        ]
    },
    {
        id: 2,
        name: 'Strength Training',
        description: 'Build muscle and strength with this workout',
        workouts: [
            {
                name: 'Squats',
                description: 'Start with 3 sets of 10 reps',
                duration: 15
            },
            {
                name: 'Push-ups',
                description: 'Start with 3 sets of 15 reps',
                duration: 10
            },
            {
                name: 'Pull-ups',
                description: 'Do 3 sets of 8 pull-ups',
                duration: 20
            },
            {
                name: 'Deadlifts',
                description: 'Start with 3 sets of 5 reps',
                duration: 25
            },
            {
                name: 'Bench Press',
                description: 'Do 3 sets of 12 reps',
                duration: 20
            },
            {
                name: 'Dumbbell Rows',
                description: 'Do 3 sets of 10 reps on each arm',
                duration: 15
            },
        ]
    },
    {
        id: 3,
        name: 'Yoga Routine',
        description: 'Yoga poses to improve flexibility',
        workouts: [
            {
                name: 'Sun Salutation',
                description: 'Perform 5 rounds of Sun Salutation',
                duration: 15
            },
            {
                name: 'Warrior Pose',
                description: 'Hold Warrior Pose for 1 minute on each side',
                duration: 10
            },
            {
                name: 'Downward-Facing Dog',
                description: 'Hold Downward-Facing Dog for 1 minute',
                duration: 5
            },
            {
                name: 'Tree Pose',
                description: 'Hold Tree Pose for 30 seconds on each side',
                duration: 10
            },
            {
                name: 'Child\'s Pose',
                description: 'Relax in Child\'s Pose for 3 minutes',
                duration: 20
            },
        ]
    },
    {
        id: 4,
        name: 'Core Strengthening',
        description: 'Focus on strengthening the core muscles',
        workouts: [
            {
                name: 'Plank',
                description: 'Hold plank position for 1 minute',
                duration: 10
            },
            {
                name: 'Russian Twists',
                description: 'Perform 3 sets of 20 reps',
                duration: 10
            },
            {
                name: 'Leg Raises',
                description: 'Perform 3 sets of 15 reps',
                duration: 15
            },
            {
                name: 'Crunches',
                description: 'Perform 3 sets of 20 reps',
                duration: 10
            },
            {
                name: 'Bicycle Crunches',
                description: 'Perform 3 sets of 20 reps',
                duration: 15
            },
        ]
    },
    {
        id: 5,
        name: 'Pilates Routine',
        description: 'Pilates exercises for strength and flexibility',
        workouts: [
            {
                name: 'Hundred',
                description: 'Perform 100 pumps of the arms while holding a V-sit',
                duration: 10
            },
            {
                name: 'Roll-Up',
                description: 'Perform 3 sets of 10 reps',
                duration: 15
            },
            {
                name: 'Single Leg Stretch',
                description: 'Perform 3 sets of 10 reps on each leg',
                duration: 15
            },
            {
                name: 'Swimming',
                description: 'Perform 3 sets of 20 reps',
                duration: 15
            },
            {
                name: 'Leg Pull Front',
                description: 'Perform 3 sets of 10 reps',
                duration: 15
            },
        ]
    },
    {
        id: 6,
        name: 'Full Body Circuit',
        description: 'Workout targeting all major muscle groups',
        workouts: [
            {
                name: 'Burpees',
                description: 'Perform 3 sets of 10 reps',
                duration: 15
            },
            {
                name: 'Mountain Climbers',
                description: 'Perform 3 sets of 20 reps',
                duration: 10
            },
            {
                name: 'Dumbbell Lunges',
                description: 'Perform 3 sets of 10 reps on each leg',
                duration: 15
            },
            {
                name: 'Push Press',
                description: 'Perform 3 sets of 10 reps',
                duration: 15
            },
            {
                name: 'Plank with Shoulder Taps',
                description: 'Hold plank position and tap shoulders for 1 minute',
                duration: 20
            },
        ]
    },
 
];
 
app.get('/api/workout-plans', (req, res) => {
    // Return mock data
    res.json(workoutPlans);
});
 
// Define route to handle root endpoint
app.get('/', (req, res) => {
    res.send('Welcome to the Social Fitness App!');
});
 
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});


Start your server using the following command.

node server.js

Steps to Create the Frontend:

Step 1: Create the frontend repository named client in the main repository.

mkdir client
cd client

Step 2: Create React project using following command.

npx create-react-app .

Step 3: Install necessary dependencies in your application using following command.

npm install axios react-router-dom

Project Structure:

Screenshot-2024-02-28-085318

Frontend structure

The updated dependencies in package.json file of frontend will look like:

  "dependencies": {
"@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"
}

Example: Create the files according to the project structure and write the following code in respective files.

CSS




/* index.css */
 
.home {
    text-align: center;
}
 
.workout-plans-container {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 20px;
}
 
.workout-plan-card {
    border: 1px solid #ccc;
    border-radius: 8px;
    padding: 20px;
    margin: 10px;
    max-width: 300px;
    background-color: #f9f9f9;
}
 
.workout-plan-card h2 {
    margin-top: 0;
    font-size: 24px;
    font-weight: bold;
}
 
.workout-plan-card p {
    margin-bottom: 10px;
}
 
.workout-image {
    width: auto;
    height: 200px;
 
}
 
.start-button {
    background-color: #4caf50;
    color: white;
    border: none;
    padding: 10px 20px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s;
    margin-top: 10px;
}
 
.start-button:hover {
    background-color: #45a049;
}
 
 
nav {
    background-color: #333;
    color: white;
    padding: 20px;
}
 
.logo {
    font-size: 24px;
    font-weight: bold;
}
 
.workout-plan {
    text-align: center;
    padding: 20px;
}
 
.workout-plan-title {
    font-size: 24px;
    font-weight: bold;
}
 
.workout-image {
    display: block;
    margin: 0 auto;
    max-width: 300px;
    height: auto;
    margin-bottom: 20px;
}
 
.workout-list {
    display: flex;
    flex-direction: column;
    align-items: center;
 
}
 
.workout-item {
    width: 100%;
    display: flex;
    align-items: center;
    margin-bottom: 10px;
    padding: 10px;
    border-radius: 5px;
    background-color: #f0f0f0;
}
 
.workout-item.selected {
    background-color: lightgreen;
}
 
.workout-item input[type="checkbox"] {
    margin-right: 10px;
}
 
.workout-item label {
    font-size: 16px;
}


Javascript




import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
 
 
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>
);


Javascript




// ./components/Home.js
import React, {
  useState,
  useEffect
} from 'react';
import {
  useNavigate
} from 'react-router-dom';
import axios from 'axios';
import '../index.css';
import Navbar from './Navbar.js';
 
 
function Home() {
  const [workoutPlans, setWorkoutPlans] = useState([]);
  const navigate = useNavigate();
 
  useEffect(() => {
      .then(response => {
        setWorkoutPlans(response.data);
      })
      .catch(error => {
        console.error('Error fetching workout plans:', error);
      });
  }, []);
 
  const handleStartWorkout = (workoutId) => {
    // Navigate to the workout page with the workout plan ID
    navigate(`/workout/${workoutId}`);
  };
 
  return (
    <div className="home">
      <Navbar />
      <h1>Workout Plans</h1>
      <div className="workout-plans-container">
        {workoutPlans.map(workoutPlan => (
          <div key={workoutPlan.id}
            className="workout-plan-card">
            <h2>{workoutPlan.name}</h2>
            <p>{workoutPlan.description}</p>
            <img src={workoutPlan.imageUrl}
              alt={workoutPlan.name}
              className="workout-image" /><br />
            <button className="start-button"
              onClick={() => handleStartWorkout(workoutPlan.id)}>
              Start Workout
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}
 
export default Home;


Javascript




import React, {
  useState,
  useEffect
} from 'react';
import {
  useParams
} from 'react-router-dom';
import axios from 'axios';
import '../index.css';
import Nav from './Navbar';
 
function WorkoutPage() {
  const { id } = useParams();
  const [workoutPlan, setWorkoutPlan] = useState(null);
  const [selectedWorkouts, setSelectedWorkouts] = useState({});
 
  useEffect(() => {
    if (!id) {
      console.error('Invalid workout plan ID:', id);
      return;
    }
 
    axios.get(`http://localhost:5000/api/workout-plans`)
      .then(response => {
        const plan = response.data.find(plan => plan.id === parseInt(id));
 
        if (plan) {
          setWorkoutPlan(plan);
          // Initialize selected workouts state
          const initialSelectedWorkouts = {};
          plan.workouts.forEach(workout => {
            initialSelectedWorkouts[workout.name] = false;
          });
          setSelectedWorkouts(initialSelectedWorkouts);
        } else {
          console.error('Workout plan not found:', id);
        }
      })
      .catch(error => {
        console.error('Error fetching workout plans:', error);
      });
  }, [id]);
 
  const handleCheckboxChange = (workoutName) => {
    setSelectedWorkouts({
      ...selectedWorkouts,
      [workoutName]: !selectedWorkouts[workoutName]
    });
  };
 
  if (workoutPlan === null) {
    return <div>Loading...</div>;
  }
 
  return (
    <div className="workout-plan">
      <Nav />
      <h1 className="workout-plan-title">
        {workoutPlan.name}
      </h1>
      <img src={workoutPlan.imageUrl}
        alt={workoutPlan.name}
        className="workout-image" />
      <p>{workoutPlan.description}</p>
      <div className="workout-list">
        {workoutPlan.workouts &&
          workoutPlan.workouts.map(workout => (
            <div key={workout.name}
              className={`workout-item ${selectedWorkouts[workout.name] ?
                  'selected' : ''}`}>
              <input
                type="checkbox"
                checked={selectedWorkouts[workout.name]}
                onChange={() => handleCheckboxChange(workout.name)}
              />
              <label>{workout.name}</label>
            </div>
          ))}
      </div>
      {Object.values(selectedWorkouts).every(value => value)
        && <div className="workout-completed">
          Workout Completed!
        </div>}
    </div>
  );
}
 
export default WorkoutPage;


Javascript




// ./components/Navbar.js
 
import React from 'react';
 
const Nav = () => {
    return (
        <nav>
            <div className="logo">
                Social Fitness App
            </div>
        </nav>
    );
}
 
export default Nav;


Javascript




// App.js
import React from 'react';
import {
    BrowserRouter as Router,
    Routes,
    Route
} from 'react-router-dom';
import Home from './components/Home';
import WorkoutPage from './components/WorkoutPage';
import Navbar from './components/Navbar';
 
const App = () => {
    return (
        <Router>
            <Navbar />
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/workout/:id"
                    element={<WorkoutPage />} />
            </Routes>
        </Router>
    );
}
 
export default App;


Start the project using the given command.

npm start

Output:

gfg67

Output



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads