Steps to Create the 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 project structure

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",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

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

Javascript




// client/src/App.js
import React from 'react';
 
import ProductList from './components/ProductList';
import Header from './components/Header';
import './App.css'// 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;
import CustomItemContext from './context/ItemContext';
 
const App = () => {
    return (
        <CustomItemContext>
            <Header />
            <ProductList />
        </CustomItemContext>
    );
};
 
export default App;


Javascript




// src/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/books");
            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




// 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 Book Store </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</p>
                <p>{product.genre}</p>
                <p style={{ fontWeight: "700", color: "brown" }}>
                    {product.author}
                </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.genre === selectedType
            );
            setSortedProducts(filtered);
        }
    };
 
    return (
        <div className="prdt-list">
            <h2 style={{ color: "green" }}>Book 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="Fiction">Fiction</option>
                        <option value="Dystopian">Dystopian</option>
                        {/* Add more options as needed */}
                    </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:

Final output



Bookstore Ecommerce App using MERN Stack

Bookstore E-commerce project is a great way to showcase your understanding of full-stack development. In this article, we’ll walk through the step-by-step process of creating a Bookstore E-commerce 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 books.

Preview of final output: Let us have a look at how the final application will look like:

Final Project Output

Similar Reads

Prerequisites:

React JS and topics like Context Api. MongoDB and Mongoose Express Node JS MERN Stack...

Approach to create Bookstore Ecommerce:

List all the requirement for the project and make the flowand structure of the project accordingly. Chooses the required dependencies and requirement which are more suitable for the project. ProductList and Header are custom components, assumed to be present in the ./components directory. CustomItemContext is imported, presumably a custom context provider. Define a functional component named App. 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. 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....

Steps to Create the Backend:

Step 1: Create a directory for project...

Steps to Create the Frontend:

...