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:
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.3 s 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; } h 2 { 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 : 2 rem; 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:
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: