Open In App

Create a Community Marketplace App using React

Last Updated : 18 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we will explore the process of developing a Community Marketplace application using React, that offers a seamless and user-friendly experience for users. The Community Marketplace App is a platform where users can buy and sell goods. It provides a convenient way for community members to trade items locally.

By following this tutorial, beginners will learn how to use React to build a modern and responsive web application.

Output Preview: Let us have a look at how the final output will look like.

Screenshot-2024-03-18-104753

Prerequisites:

Approach to build Community Marketplace App:

  • Create a new ReactJS project using a tool like Create React App. Install necessary libraries such as React Router for routing, Bootstrap for styling, and any other libraries needed for state management or API calls.
  • Create components for the navbar, product listings, product details, adding new products form, and other necessary components. Organize the components in a structured manner for better maintainability and reusability.
  • Allow users to list items they want to sell by creating a form component for adding new products. Include fields for images, descriptions, prices, contact details, etc., in the form for users to fill out when listing their products.
  • Implement search functionality to allow users to search for specific products based on keywords. Implement filter functionality to display products from a specific category or based on other criteria chosen by the user.
  • Utilize the useState hook to manage the states of various components in the application, such as form data and search/filter criteria. Use React Router to set up routing for different pages of the application, such as the product listings page, product details page, and add product page.
  • Utilize useParams hook from React Router to get the Product ID and display details about a specific product on the product details page.

Steps to build Community Marketplace App:

Step 1: Create a reactJS application by using this command

npx create-react-app marketplace

Step 2: Navigate to project directory

cd marketplace

Step 3: Install the necessary packages/libraries in your project using the following commands.

npm install bootstrap
npm install react-router-dom
npm install react-icons --save
npm install react-toastify

Project Structure:

Screenshot-(40)


The updated dependencies in package.json file will look like:

"dependencies": {
"@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-icons": "^5.0.1",
"react-router-dom": "^6.22.3",
"react-scripts": "5.0.1",
"react-toastify": "^10.0.4",
"web-vitals": "^2.1.4"
}

Example: Illustartipon to design a Community Marketplace App with React.

JavaScript
// App.js

import React, { useState, useEffect } from 'react';
import { Route, Routes } from 'react-router-dom';

import { BrowserRouter } from 'react-router-dom'
import 'bootstrap/dist/css/bootstrap.min.css';

import ProductList from './components/ProductList';
import ProductDetail from './components/ProductDetail';
import AddProduct from './components/AddProduct';
import Navbar from './components/Navbar';

const App = () => {

return (
    <BrowserRouter>
    <Navbar />
        <Routes>
        <Route path="/" element={<ProductList />} />
        <Route path="/addProduct" element={<AddProduct />} />
        <Route path="/products/:productId" element={<ProductDetail/>} />
        </Routes>
    </BrowserRouter>
);
};

export default App;
JavaScript
// Navbar.js

import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Link } from 'react-router-dom';

const Navbar = () => {
    return (
        <nav className="navbar navbar-expand-lg 
                        navbar-light bg-primary 
                        text-light">
            <div className="container">
                <a className="navbar-brand text-light 
                              display-6" href="#">
                    Marketplace
                </a>
                <button className="navbar-toggler" 
                        type="button" data-toggle="collapse" 
                        data-target="#navbarNav"
                    aria-controls="navbarNav" aria-expanded="false" 
                                   aria-label="Toggle navigation">
                    <span className="navbar-toggler-icon"></span>
                </button>
                <div className="collapse navbar-collapse" 
                     id="navbarNav">
                    <ul className="navbar-nav mr-auto">
                        <li className="nav-item">
                            <Link className="nav-link text-light" 
                                  to="/">
                                Products
                            </Link>
                        </li>
                    </ul>
                    <ul className="navbar-nav">
                        <li className="nav-item">
                            <Link className="nav-link text-light" 
                                  to="/addProduct">
                                  Sell your Product
                            </Link>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    );
};

export default Navbar;
JavaScript
// AddProduct.js

import React, { useState } from 'react';
import { toast, ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const ProductForm = () => {
    const prods = JSON.parse(localStorage.getItem('products')) || [];

    const [productName, setProductName] = useState('');
    const [description, setDescription] = useState('');
    const [price, setPrice] = useState('');
    const [image, setImage] = useState(null);
    const [id, setId] = useState(prods.length + 1);
    const [category, setCategory] = useState('');
    const [sellerName, setSellerName] = useState('');
    const [contactDetails, setContactDetails] = useState('');
    const [products, setProducts] = useState(prods);

    const handleProductNameChange = (e) => {
        setProductName(e.target.value);
    };

    const handleDescriptionChange = (e) => {
        setDescription(e.target.value);
    };

    const handlePriceChange = (e) => {
        setPrice(e.target.value);
    };

    const handleImageChange = (e) => {
        const file = e.target.files[0];
        setImage(file);
    };

    const handleCategoryChange = (e) => {
        setCategory(e.target.value);
    };

    const handleSellerNameChange = (e) => {
        setSellerName(e.target.value);
    };

    const handleContactDetailsChange = (e) => {
        setContactDetails(e.target.value);
    };

    const handleSubmit = (e) => {
        e.preventDefault();

        const errors = {};
        if (!productName.trim()) {
            errors.productName = 'Product Name is required';
        }
        if (!description.trim()) {
            errors.description = 'Description is required';
        }
        if (!price.trim()) {
            errors.price = 'Price is required';
        }
        if (!category.trim()) {
            errors.category = 'Category is required';
        }
        if (!image) {
            errors.image = 'Image is required';
        }
        if (!sellerName.trim()) {
            errors.sellerName = 'Seller Name is required';
        }
        if (!contactDetails.trim()) {
            errors.contactDetails = 'Contact Details are required';
        }

        if (Object.keys(errors).length === 0) {
            // Convert the image file to base64
            const reader = new FileReader();
            reader.onloadend = () => {
                const base64Image = reader.result;

                // Create a product object
                const product = {
                    id: id,
                    productName,
                    description,
                    price,
                    image: base64Image,
                    quantity: 1,
                    category,
                    sellerName,
                    contactDetails,
                };

                // Update the local storage
                const updatedProducts = [...products, product];
                localStorage.setItem(
                    'products', JSON.stringify(updatedProducts));

                // Update the state
                setProducts(updatedProducts);
                setId(id + 1);

                // Reset form fields
                setProductName('');
                setDescription('');
                setPrice('');
                setImage(null);
                setCategory('');
                setSellerName('');
                setContactDetails('');

                // Show success message
                toast.success('Product added successfully');
            };

            reader.readAsDataURL(image);
        } else {
            // Show error messages
            Object.values(errors).forEach((error) => {
                toast.error(error);
            });
        }
    };

    return (
        <div className="container" style={{ width: '70%' }}>
            <h2>Add Product</h2>
            <form onSubmit={handleSubmit}>
                <div className="form-group">
                    <label htmlFor="productName">
                        Product Name:
                    </label>
                    <input
                        type="text"
                        className="form-control"
                        id="productName"
                        value={productName}
                        onChange={handleProductNameChange}
                    />
                </div>
                <div className="form-group">
                    <label htmlFor="description">
                        Description:
                    </label>
                    <textarea
                        className="form-control"
                        id="description"
                        value={description}
                        onChange={handleDescriptionChange}
                    ></textarea>
                </div>
                <div className="form-group">
                    <label htmlFor="price">Price:</label>
                    <input
                        type="text"
                        className="form-control"
                        id="price"
                        value={price}
                        onChange={handlePriceChange}
                    />
                </div>
                <div className="form-group">
                    <label htmlFor="category">Category:</label>
                    <select
                        className="form-control"
                        id="category"
                        value={category}
                        onChange={handleCategoryChange}
                    >
                        <option value="">Select a category</option>
                        <option value="tools">Tools</option>
                        <option value="clothes">Clothing</option>
                        <option value="sports">Sports</option>
                        <option value="furniture">Furniture</option>
                        <option value="other">Other</option>
                    </select>
                </div>
                <div className="form-group">
                    <label htmlFor="sellerName">Seller Name:</label>
                    <input
                        type="text"
                        className="form-control"
                        id="sellerName"
                        value={sellerName}
                        onChange={handleSellerNameChange}
                    />
                </div>
                <div className="form-group">
                    <label htmlFor="contactDetails">
                        Contact Details:
                    </label>
                    <input
                        type="text"
                        className="form-control"
                        id="contactDetails"
                        value={contactDetails}
                        onChange={handleContactDetailsChange}
                    />
                </div>
                <div className="form-group mt-3">
                    <label htmlFor="image">Image:</label>
                    <input
                        type="file"
                        className="form-control-file"
                        id="image"
                        accept="image/*"
                        onChange={handleImageChange}
                    />
                </div>
                <button type="submit" 
                        className="btn btn-primary mt-3">
                    Submit
                </button>
            </form>
            <ToastContainer />
        </div>
    );
};

export default ProductForm;
JavaScript
// ProductList.js

import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const ProductList = () => {
    const [searchTerm, setSearchTerm] = useState('');
    const [selectedCategory, setSelectedCategory] = useState(null);
    const products =
        JSON.parse(localStorage.getItem('products')) || [];
    const categories =
        [...new Set(products.map((product) => product.category))];

    const filteredProducts = products.filter(
        (product) =>
            product.productName
                   .toLowerCase()
                   .includes(searchTerm.toLowerCase()) &&
           (selectedCategory?product.category === selectedCategory:true)
    );

    return (
        <div className='container mt-3'>
            <div className='btn-group mb-3'
                role='group'
                aria-label='Categories'>
                <button
                    type='button'
                    className={
`btn ${selectedCategory === null ? 'btn-primary' : 'btn-secondary'}`}
                    onClick={() => setSelectedCategory(null)}
                >
                    All
                </button>
                {categories.map((category) => (
                    <button
                        key={category}
                        type='button'
                        className={
`btn ${selectedCategory === category ? 'btn-primary':'btn-secondary'}`}
                        onClick={() => setSelectedCategory(category)}>
                        {category}
                    </button>
                ))}
            </div>
            <input
                type='text'
                placeholder='Search products...'
                value={searchTerm}
                onChange={(e) => setSearchTerm(e.target.value)}
                className='form-control mb-3'
            />
            <div className='row'>
                {filteredProducts.map((product) => (
                    <div key={product.id}
                        className='col-md-3 mb-4'>
                        <div className='card'
                            style={{ width: '100%' }}>
                            <img
                                src={product.image}
                                className='card-img-top'
                                alt={product.name}
                                style={{
                                    objectFit: 'cover',
                                    width: '200px',
                                    height: '200px'
                                }}
                            />
                            <div className='card-body'>
                                <h5 className='card-title'
                                    style={{
                                        fontSize: '1.25rem',
                                        fontWeight: 'bold'
                                    }}>
                                    {product.productName}
                                </h5>
                                <p className='card-text'
                                    style={{
                                        fontSize: '1rem',
                                        color: 'gray'
                                    }}>
                                    ₹{product.price}
                                </p>
                                <Link to={`/products/${product.id}`}>
                                    <button className='btn btn-primary'>
                                        View Details
                                    </button>
                                </Link>
                            </div>
                        </div>
                    </div>
                ))}
            </div>
            <ToastContainer />
        </div>
    );
};

export default ProductList;
JavaScript
// ProductDetail.js

import React, { useState } from 'react';
import { useParams } from 'react-router-dom';

function getProductById(id) {
    const products = JSON.parse(
        localStorage.getItem('products')) || [];
    return products.find(
        product => product.id === parseInt(id));
}

function ProductDetail() {
    const { productId } = useParams();
    const product = getProductById(productId);

    const [showContactForm, setShowContactForm] = useState(false);
    const [formData, setFormData] = useState({
        name: '',
        email: '',
        message: ''
    });

    const handleChange = (e) => {
        const { name, value } = e.target;
        setFormData({ ...formData, [name]: value });
    };

    const handleSubmit = (e) => {
        e.preventDefault();

        // Here you can handle the form submission, 
        // e.g., send an email or store the message in a database
        console.log(formData);
        setFormData({ name: '', email: '', message: '' });
    };

    return (
        <div className="container mt-3"
            style={{
                maxWidth: '800px', margin: 'auto',
                padding: '20px', border: '1px solid #ccc',
                borderRadius: '5px',
                boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
            }}>
            {product ? (
                <div>
                    <img src={product.image}
                        alt={product.productName}
                        style={{
                            maxWidth: '60%', height: 'auto',
                            marginBottom: '20px'
                        }} />
                    <h1 style={{
                        fontFamily: 'Arial, sans-serif',
                        fontSize: '24px', fontWeight: 'bold',
                        marginBottom: '10px'
                    }}>
                        {product.productName}
                    </h1>
                    <p style={{
                        fontFamily: 'Arial, sans-serif',
                        fontSize: '16px', marginBottom: '10px'
                    }}>
                        {product.description}
                    </p>
                    <p style={{
                        fontFamily: 'Arial, sans-serif',
                        fontSize: '16px', marginBottom: '10px'
                    }}>
                        Price: ₹
                        {product.price}
                    </p>
                    <p style={{
                        fontFamily: 'Arial, sans-serif',
                        fontSize: '16px', marginBottom: '10px'
                    }}>
                        Seller: {product.sellerName}
                    </p>
                    <p style={{
                        fontFamily: 'Arial, sans-serif',
                        fontSize: '16px', marginBottom: '10px'
                    }}>
                        Contact Details: {product.contactDetails}
                    </p>
                    {!showContactForm && (
                        <button className="btn btn-primary"
                            onClick={() => setShowContactForm(true)}>
                            Contact Seller
                        </button>
                    )}
                    {showContactForm && (
                        <div>
                            <h2 style={{
                                fontFamily: 'Arial, sans-serif',
                                fontSize: '20px', fontWeight: 'bold',
                                marginBottom: '10px'
                            }}>
                                Contact Seller
                            </h2>
                            <form onSubmit={handleSubmit}>
                                <div className="form-group">
                                    <label htmlFor="name">Name:</label>
                                    <input type="text"
                                           className="form-control"
                                           id="name"
                                           name="name" 
                                           value={formData.name}
                                           onChange={handleChange} />
                                </div>
                                <div className="form-group">
                                    <label htmlFor="email">
                                        Email:
                                    </label>
                                    <input type="email"
                                           className="form-control" 
                                           id="email"
                                           name="email" 
                                           value={formData.email}
                                           onChange={handleChange} />
                                </div>
                                <div className="form-group">
                                    <label htmlFor="message">
                                        Message:
                                    </label>
                                    <textarea className="form-control"
                                              id="message" 
                                              name="message"
                                              value={formData.message}
                                              onChange={handleChange}>
                                    </textarea>
                                </div>
                                <button type="submit" 
                                        className="btn btn-primary">
                                    Send Message
                                </button>
                            </form>
                        </div>
                    )}
                </div>
            ) : (
                <p>Product not found</p>
            )}
        </div>
    );
}

export default ProductDetail;

Step to Run Application: Run the application using the following command from the root directory of the project

npm start

Output: Your project will be shown in the URL http://localhost:3000/

cde



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads