Open In App

Fruit and Vegetable Market Shop using MERN

Last Updated : 05 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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.

Screenshot-2567-01-03-at-232111-(1)

Prerequisites:

Approach to create Fruit and Vegetable Market Shop in MERN:

  1. Import Statements:
    • Import necessary dependencies and components.
    • React is imported for defining React components.
    • ProductList and Header are custom components, assumed to be present in the ./components directory.
    • CustomItemContext is imported, presumably a custom context provider.
  2. Functional Component:
    • Define a functional component named App.
  3. Context Provider:
    • Wrap the Header and ProductList components inside the CustomItemContext provider. This suggests that the components within this provider have access to the context provided by CustomItemContext.
  4. Component Rendering:
    • Render the following components:
      • CustomItemContext: Presumably, this is a context provider that wraps its child components (Header and ProductList). The purpose of this context is not clear from the provided code snippet.
      • Header component.
      • ProductList component.

Steps to Create the Backend:

Step 1: Create a directory for project

npm init backend


Step 2: Open project using the command

cd backend


Step 3: Installing the required packages

npm install express mongoose cors


Project Structure:

Screenshot-2567-01-04-at-000243

Backend project 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.

Javascript




// server.js
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const PORT = process.env.PORT || 5000;
const cors = require('cors');
 
  {
    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:
      },
      {
        name: 'Banana',
        type: 'Fruit',
        description: 'Rich in potassium',
        price: 75,
        image:
      },
      {
        name: 'Orange',
        type: 'Fruit',
        description: 'Packed with vitamin C',
        price: 200,
        image:
      },
      {
        name: 'Carrot',
        type: 'Vegetable',
        description: 'Healthy and crunchy',
        price: 100,
        image:
      },
      {
        name: 'Broccoli',
        type: 'Vegetable',
        description: 'Nutrient-rich greens',
        price: 175,
        image:
      },
      {
        name: 'Grapes',
        type: 'Fruit',
        description: 'Sweet and juicy',
        price: 250,
        image:
      },
      {
        name: 'Strawberry',
        type: 'Fruit',
        description: 'Delicious red berries',
        price: 300,
        image:
      },
      {
        name: 'Lettuce',
        type: 'Vegetable',
        description: 'Crisp and fresh',
        price: 120,
        image:
      },
      {
        name: 'Tomato',
        type: 'Vegetable',
        description: 'Versatile and flavorful',
        price: 180,
        image:
      },
      {
        name: 'Cucumber',
        type: 'Vegetable',
        description: 'Cool and hydrating',
        price: 130,
        image:
      },
 
    ];
 
    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.js


Steps to Create the Frontend:

Step 1: Set up React frontend using the command.

npx create-react-app client


Step 2: Navigate to the project folder using the command.

cd client


Project Structure:

Screenshot-2567-01-04-at-000408

Client /Frontend project 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"
}


Javascript




// 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;


Javascript




//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;


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 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;


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/Kg
                </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='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;


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: 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;
 }


To start frontend code:

npm start


Output:

Untitled-design-(27)

Final Project Output

Output of Data Saved in Database:

fooddb

Db



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads