Open In App

E-commerce Website using MERN Stack

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

The project is an E-commerce website built using the MERN (MongoDB, Express.js, React, Node.js) stack. It provides a platform for users to view and purchase various products. The server-side (Node.js with Express) manages the API for product data stored in a MongoDB database. The client-side (React) handles the user interface and interacts with the server to fetch and display product information.

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

Screenshot-2024-03-19-013706

Prerequisites:

Approach to create E-commerce Website:

  • Server-side API for fetching product data
  • React components for displaying product information
  • MongoDB for storing product details
  • CORS middleware to handle cross-origin requests

Steps to Create the E-commerce Website with MERN Stack:

1. Setting up backend

Create a directory for project

mkdir server
cd server

Step 2: Initialized the Express app and installing the required packages

npm init -y
npm i express mongoose cors

Project Structure(Backend):

Screenshot-2024-03-10-104441

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

"dependencies": {
"cors": "^2.8.5",
"express": "^4.18.3",
"mongoose": "^8.2.1",
}

Example: Create `index.js` and write the below code.

Javascript
// index.js
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const PORT = process.env.PORT || 5000;
const cors = require('cors');
 //replace the link with your mongodb atlas link
mongoose.connect('your_mongodb_url',
  {
    useNewUrlParser: true,
    useUnifiedTopology: true
  }
);
 
app.use(express.json());
app.use(cors()); // Use the cors middleware
 
const productSchema = new mongoose.Schema({
  name: String,
  type: String,
  description: String,
  price: Number,
  image: String,
});
 
const Product = mongoose.model('Product', productSchema);
 
// Function to seed initial data into the database
const seedDatabase = async () => {
  try {
    await Product.deleteMany(); // Clear existing data
 
    const products = [
      {
        name: "Men's Casual T-shirt",
        type: 'Men',
        description: 'Comfortable and stylish casual T-shirt for men',
        price: 350,
        image: 
'https://media.geeksforgeeks.org/wp-content/uploads/20230407153931/gfg-tshirts.jpg'
      },
      {
        name: 'Luxury bag',
        type: 'Not Applicable', 
        description: 'Elegant luxury bag with leather strap',
        price: 2500,
        image: 
'https://media.geeksforgeeks.org/wp-content/uploads/20230407154213/gfg-bag.jpg'
      },
      {
        name: "Hoodie",
        type: 'Men',
        description: 'Light and classy hoodies for every seasons ',
        price: 450,
        image: 
'https://media.geeksforgeeks.org/wp-content/uploads/20230407153938/gfg-hoodie.jpg'
      },
      {
        name: 'Remote Control Toy car',
        type: 'Not Applicable', 
        description: 'High-quality Toy car for fun and adventure',
        price: 1200,
        image: 
'https://media.geeksforgeeks.org/wp-content/uploads/20240122182422/images1.jpg'
      },
      {
        name: 'Books',
        type: 'Women',
        description: 'You wll have a great time reading .',
        price: 5000,
        image: 
'https://media.geeksforgeeks.org/wp-content/uploads/20240110011854/reading-925589_640.jpg'
      },
      {
        name: 'Bag',
        type: 'Men', 
        description: 'Comfortable and supportive Bag ',
        price: 800,
        image: 
'https://media.geeksforgeeks.org/wp-content/uploads/20230407154213/gfg-bag.jpg'
      },
      {
        name: 'Winter hoodies for women',
        type: 'Women',
        description: 'Stay cozy in style with our womens hoodie, crafted for comfort ',
        price: 250,
        image: 
'https://media.geeksforgeeks.org/wp-content/uploads/20230407153938/gfg-hoodie.jpg'
      },
      
      {
        name: 'Honda car ',
        type: 'Men',
        description: 'Powerful Honda car with comfy driving',
        price: 700,
        image: 
'https://media.geeksforgeeks.org/wp-content/uploads/20240122184958/images2.jpg'
      }
    ];
    
  
    
      
 
    await Product.insertMany(products);
    console.log('Database seeded successfully');
  } catch (error) {
    console.error('Error seeding database:', error);
  }
};
 
// Seed the database on server startup
seedDatabase();
 
// Define API endpoint for fetching all products
app.get('/api/products', async (req, res) => {
  try {
    // Fetch all products from the database
    const allProducts = await Product.find();
 
    // Send the entire products array as JSON response
    res.json(allProducts);
  } catch (error) {
    console.error(error);
    res.status(500)
      .json({ error: 'Internal Server Error' });
  }
});
 
app.listen(PORT, () => {
  console.log(
    `Server is running on port ${PORT}`
  );
});

Start the backend server with the following command:

node index.js

2. Creating FrontEnd

Step 1: Set up React frontend using the command.

npx create-react-app client
cd client

Step 2: Install the required dependencies.

npm i @fortawesome/free-solid-svg-icons
npm i @fortawesome/react-fontawesome

Project Structure(Frontend):

Screenshot-2024-03-10-104433

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

"dependencies": {
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"axios": "^1.6.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.3",
"react-scripts": "5.0.1",
"sass": "^1.71.1",
"web-vitals": "^2.1.4"
}

Example: Create the required files and write the following code.

CSS
/* App.css */
.cart-items {
  border-radius: 50%;
  background-color: rgb(20, 158, 105);
  font-weight: 700;
  color: aliceblue;
  width: 30px;
  height: 30px;
  font-size: 1.5rem;
  padding: 10px;
  position: relative;
  top: 10px;
  left: 30px;
}

.header {
  display: flex;
  justify-content: space-evenly;
  align-items: center;
  padding: 10px;
  border-bottom: 1px solid #ccc;
}

/* ProductItem.css */
.product-card {
  border: 1px solid #ddd;
  border-radius: 8px;
  width: fit-content;
  padding: 16px;
  margin: 16px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  background-color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.product-image {
  width: 200px;
  height: 200px;
  object-fit: cover;
  border-radius: 10px;
  margin-bottom: 12px;
  transition: transform 0.3s ease-in-out;
}

.product-image:hover {
  transform: scale(1.1);
  /* Enlarge the image on hover */
}

.product-details {
  text-align: center;
}

.item-card {
  display: flex;
  flex-wrap: wrap;
}

h2 {
  text-align: center;
  color: #333;
}

.filter-btn {
  display: flex;
  flex-direction: row;
  padding: 10px;
  gap: 10px;
  justify-content: center;
}

.prdt-list {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.cart-num {
  margin-bottom: 40px;
  cursor: pointer;
  font-size: 1.2rem;
}

.buy-now-btn {
  background-color: rgb(11, 162, 11);
  color: white;
  padding: 8px 15px;
  border-radius: 10px;
  font-size: 1.5rem;
  position: fixed;
  top: 30%;
  right: 10px;
  cursor: pointer;
}

.buy-now-btn:hover {
  background-color: rgb(113, 230, 113);
  color: brown;
}

.ecom {
  background-color: green;
  color: white;
  padding: 8px 15px;
  border-radius: 10px;
  font-size: 1.2rem;
}
Javascript
// src/index.js
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
// App.js
import React from 'react';

import ProductList
    from './components/ProductList';
import Header
    from './components/Header';
import './App.css'
import CustomItemContext
    from './context/ItemContext';

const App = () => {
    return (
        <CustomItemContext>
            <Header />
            <ProductList />
        </CustomItemContext>
    );
};

export default App;
Javascript
// client/src/components/Header.js
import React, { useContext } from 'react';
import { FontAwesomeIcon }
    from '@fortawesome/react-fontawesome'
import { faCartShopping }
    from '@fortawesome/free-solid-svg-icons'
import { itemContext } from '../context/ItemContext';

const Navbar = () => {

    const { itemsInCart, totalPrice } = useContext(itemContext);

    return (
        <nav className='navbar'>
            <div className='navbar-brand'>
                <h1 className='ecom'>
                    My Ecommerce Website
                </h1>
            </div>
            <div className='navbar-items'>
                <h3 style={{ color: "green" }}>
                    Total Price: {totalPrice}
                </h3>
                <div className='cart-num'>
                    <FontAwesomeIcon
                        icon={faCartShopping} size="2x" />
                    <div className='cart-items'>
                        {itemsInCart}
                    </div>
                </div>
            </div>
        </nav>
    );
};

export default Navbar;
Javascript
// client/src/components/ProductItem.js
import React, { useContext } from 'react';
import { itemContext } from '../context/ItemContext';

const ProductItem = ({ product }) => {
    const { addToCart, removeFromCart } = useContext(itemContext)
    const handleAddToCart = (product) => {
        console.log(product)
        addToCart(product)

    };
    const handleRemoveToCart = (product) => {
        console.log("product removed", product)
        removeFromCart(product)

    };
    return (
        <div className="product-card">
            <img className="product-image"
                src={product.image}
                alt={product.name} />
            <div className="product-details">
                <h3 style={{ fontWeight: "700" }}>
                    {product.name}
                </h3>
                <p style={{ fontWeight: "300" }}>
                    {product.description}
                </p>
                <p style={{ fontWeight: "500" }}>
                    Price: {product.price} Rs
                </p>
                <button onClick={
                    () => handleAddToCart(product)
                }>
                    Add to Cart
                </button>
                <button onClick={
                    () =>
                        handleRemoveToCart(product)
                }>
                    -
                </button>
            </div>
        </div>
    );
};

export default ProductItem;
Javascript
// client/src/components/ProductList.js

import React,
{
    useContext,
    useEffect,
    useState
} from 'react';
import ProductItem from './ProductItem';
import { itemContext } from '../context/ItemContext';

const ProductList = () => {
    const { products } = useContext(itemContext);
    // Keep a local state for sorted products
    const [sortedProducts, setSortedProducts] =
        useState([...products]);
    const [minPrice, setMinPrice] = useState(0);
    const [maxPrice, setMaxPrice] = useState(3000);
    // 'all' represents no type filter
    const [selectedType, setSelectedType] = useState('all');

    useEffect(() => {
        setSortedProducts([...products])
    }, [products])

    const handleSortByPrice = () => {
        const sorted = [...sortedProducts]
            .sort((a, b) => a.price - b.price);
        setSortedProducts(sorted);
    };

    const handleFilterByPriceRange = () => {
        const filtered =
            products.filter(
                (product) =>
                    product.price >= minPrice &&
                    product.price <= maxPrice);
        setSortedProducts(filtered);
    };

    const handleFilterByType = () => {
        if (selectedType === 'all') {
            // Reset the type filter
            setSortedProducts([...products]);
        } else {
            const filtered =
                products.filter(
                    (product) =>
                        product.type === selectedType);
            setSortedProducts(filtered);
        }
    };

    return (
        <div className='prdt-list'>
            <h2>Product List</h2>
            <div className='filter-btn'>
                <button onClick={handleSortByPrice}>
                    Sort by Price
                </button>
                <label>
                    Min Price:
                    <input type='number' value={minPrice}
                        onChange={
                            (e) =>
                                setMinPrice(Number(e.target.value))
                        } />
                </label>
                <label>
                    Max Price:
                    <input type='number' value={maxPrice}
                        onChange={
                            (e) =>
                                setMaxPrice(Number(e.target.value))
                        } />
                </label>
                <button onClick={() => handleFilterByPriceRange()}>
                    Filter by Price Range
                </button>
                <label>
                    Filter by Type:
                    <select value={selectedType}
                        onChange={
                            (e) =>
                                setSelectedType(e.target.value)
                        }>
                        <option value='all'>
                            All
                        </option>
                        <option value='Men'>Men</option>
                        <option value='Women'>Women</option>
                    </select>
                </label>

                <button onClick={handleFilterByType}>
                    Filter by Type
                </button>
            </div>

            <ul className='item-card'>
                {sortedProducts.map((product) => (
                    <ProductItem key={product._id}
                        product={product} />
                ))}
            </ul>
            <div className='buy-now-btn'>Buy Now</div>
        </div>
    );
};

export default ProductList;

Start frontend code:

npm start

Output:
ww



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads