E-commerce Website using MERN Stack
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.
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):
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.
// 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.w3wiki.net/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.w3wiki.net/wp-content/uploads/20230407154213/gfg-bag.jpg'
},
{
name: "Hoodie",
type: 'Men',
description: 'Light and classy hoodies for every seasons ',
price: 450,
image:
'https://media.w3wiki.net/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.w3wiki.net/wp-content/uploads/20240122182422/images1.jpg'
},
{
name: 'Books',
type: 'Women',
description: 'You wll have a great time reading .',
price: 5000,
image:
'https://media.w3wiki.net/wp-content/uploads/20240110011854/reading-925589_640.jpg'
},
{
name: 'Bag',
type: 'Men',
description: 'Comfortable and supportive Bag ',
price: 800,
image:
'https://media.w3wiki.net/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.w3wiki.net/wp-content/uploads/20230407153938/gfg-hoodie.jpg'
},
{
name: 'Honda car ',
type: 'Men',
description: 'Powerful Honda car with comfy driving',
price: 700,
image:
'https://media.w3wiki.net/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):
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.
/* 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;
}
// 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>
);
// 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;
// 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;
// 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;
// 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:
Contact Us