In this comprehensive guide, we'll walk through the step-by-step process of creating a Fruit and Vegetable Market Shop using the MERN (MongoDB, Express.js, React, Node.js) stack. This project will showcase how to set up a full-stack web application where users can view, filter, and purchase various fruits and vegetables.
Preview of final output: Let us have a look at how the final output will look like.
.jpg)
Prerequisites:
Approach to create Fruit and Vegetable Market Shop in MERN:
- Import Statements:
- Import necessary dependencies and components.
- React is imported for defining React components.
ProductListandHeaderare custom components, assumed to be present in the./componentsdirectory.CustomItemContextis imported, presumably a custom context provider.
- Functional Component:
- Define a functional component named
App.
- Define a functional component named
- Context Provider:
- Wrap the
HeaderandProductListcomponents inside theCustomItemContextprovider. This suggests that the components within this provider have access to the context provided byCustomItemContext.
- Wrap the
- Component Rendering:
- Render the following components:
CustomItemContext: Presumably, this is a context provider that wraps its child components (HeaderandProductList). The purpose of this context is not clear from the provided code snippet.Headercomponent.ProductListcomponent.
- Render the following components:
Steps to Create the Backend:
Step 1: Create a directory for project
npm init backendStep 2: Open project using the command
cd backendStep 3: Installing the required packages
npm install express mongoose corsProject Structure:

The updated dependencies in package.json file for backend will look like:
"dependencies": {
"cors": "^2.8.5",
"express": "^4.18.2",
"mongoose": "^8.0.0",
}
Example: Create `server.js` and paste the below code.
// server.js
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const PORT = process.env.PORT || 5000;
const cors = require('cors');
mongoose.connect('mongodb://localhost/fruitvegmarke',
{
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: 'Apple', type: 'Fruit',
description: 'Fresh and crispy',
price: 150,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20240104142542/apple.jpg'
},
{
name: 'Banana',
type: 'Fruit',
description: 'Rich in potassium',
price: 75,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20240104142554/banana.jpg'
},
{
name: 'Orange',
type: 'Fruit',
description: 'Packed with vitamin C',
price: 200,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20240104142641/orange.jpg'
},
{
name: 'Carrot',
type: 'Vegetable',
description: 'Healthy and crunchy',
price: 100,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20240104142613/carrot.jpg'
},
{
name: 'Broccoli',
type: 'Vegetable',
description: 'Nutrient-rich greens',
price: 175,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20240104142601/brocoli.jpg'
},
{
name: 'Grapes',
type: 'Fruit',
description: 'Sweet and juicy',
price: 250,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20240104142629/grapes.jpg'
},
{
name: 'Strawberry',
type: 'Fruit',
description: 'Delicious red berries',
price: 300,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20240104142657/strawberry.jpg'
},
{
name: 'Lettuce',
type: 'Vegetable',
description: 'Crisp and fresh',
price: 120,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20240104142635/lettue.jpg'
},
{
name: 'Tomato',
type: 'Vegetable',
description: 'Versatile and flavorful',
price: 180,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20240104142704/tomato.jpg'
},
{
name: 'Cucumber',
type: 'Vegetable',
description: 'Cool and hydrating',
price: 130,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20240104142621/cocumber.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:
node server.jsSteps to Create the Frontend:
Step 1: Set up React frontend using the command.
npx create-react-app clientStep 2: Navigate to the project folder using the command.
cd clientProject Structure:

The updated dependencies in package.json for frontend will look like:
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}
/*App.css*/
.cart-items {
border-radius: 50%;
background-color: rgb(20, 158, 105);
font-weight: 700;
color: aliceblue;
width: 30px;
height: 30px;
font-size: 30px;
padding: 10px;
top: 10px;
position: relative;
left: 30px;
}
.header {
display: flex;
justify-content: space-evenly;
align-items: center;
padding: 10px;
border-bottom: 1px sold #ccc;
}
/* card */
/* client/src/components/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;
}
.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;
}
.buy-now-btn {
background-color: rgb(11, 162, 11);
color: white;
padding: 5px 10px;
border-radius: 10px;
font-size: 2rem;
position: fixed;
top: 30%;
right: 10px;
cursor: pointer;
}
.buy-now-btn:hover {
background-color: rgb(113, 230, 113);
color: brown;
}
.gfg {
background-color: green;
color: white;
padding: 5px 10px;
border-radius: 10px;
}
// client/src/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;
//context/ItemContext.js
import {
createContext,
useEffect,
useState
} from 'react';
const itemContext = createContext();
// creating custom provider
function CustomItemContext({ children }) {
const [products, setProducts] = useState([]);
const [cart, setCart] = useState([]);
const [itemsInCart, setItemsInCart] = useState(0);
const [totalPrice, setTotalPrice] = useState(0)
// useEffect to load all the vegetables
useEffect(() => {
// Fetch products from the backend and dispatch 'SET_PRODUCTS' action
const fetchData = async () => {
const response =
await fetch('http://localhost:5000/api/products');
const products = await response.json();
// console.log(products)
setProducts(products);
};
fetchData();
}, []);
const addToCart = (product) => {
setTotalPrice(totalPrice + product.price)
setCart([...cart, product]);
setItemsInCart(itemsInCart + 1);
};
const removeFromCart = (product) => {
const index =
cart.findIndex(
(prdt) =>
prdt._id === product._id);
console.log(index);
if (index !== -1) {
// Item found in the cart
// Now you can remove it from the cart array
const updatedCart = [...cart];
updatedCart.splice(index, 1);
setTotalPrice(totalPrice - cart[index].price);
setCart(updatedCart);
setItemsInCart(itemsInCart - 1);
} else {
console.log("Item not found in the cart");
}
};
return (
// default provider
<itemContext.Provider value={
{
products, addToCart,
removeFromCart,
itemsInCart, totalPrice
}}>
{children}
</itemContext.Provider>
);
}
export { itemContext };
export default CustomItemContext;
// 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 Header = () => {
const { itemsInCart, totalPrice } = useContext(itemContext)
return (
<div className='header' >
<h1 className='gfg'>
GFG Fruit & Vegetable Market
</h1>
<h3 style={{ color: "green" }}>
Total Price: {totalPrice}
</h3>
<div className='cart-num'>
<div className='cart-items'>
{itemsInCart}
</div>
<FontAwesomeIcon icon={faCartShopping} size="4x" />
</div>
</div>
);
};
export default Header;
// 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/Kg
</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='Fruit'>Fruit</option>
<option value='Vegetable'>Vegetable</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;
To start frontend code:
npm startOutput:
Output of Data Saved in Database:
