📝 CometChat tutorial: Marketplace Site With React and Real-time Chat (Amazon Clone)
Tags: programming, realtime, chatting
Published: 2021-05-07 17:21:34

---
title: 📝 CometChat tutorial: Marketplace Site With React and Real-time Chat (Amazon Clone)
published: true
description: In this tutorial, you will learn how to create a React App from scratch that will serve as a basic Amazon Clone with chat capabilities right on the product page using some of CometChat’s features and components with easy steps to follow along!
tags: Programming, Realtime, Chatting
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54c5v1kq4gt591093dmg.jpg
main_image: ![CometChat Use Case Tutorial Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54c5v1kq4gt591093dmg.jpg)
canonical_url: https://www.cometchat.com/tutorials/build-marketplace-site-with-react-and-real-time-chat-amazon-clone
---

## Prerequisites

In order to complete this tutorial and have a working application, some knowledge in the following can be required:


- Basic knowledge of React, React hooks and general JavaScript,
- [Firebase](https://firebase.google.com) features knowledge,
- [TailwindCSS](https://tailwindcss.com/), and
- Any text editor (I recommend [Visual Studio Code](https://code.visualstudio.com/))

# Introduction

Have you ever been browsing through Amazon trying to find that specific product that you need to follow particular characteristics? You eventually find it, but you have some questions that the product description just doesn’t answer. 

**How great would it be if you could chat with the seller,** **on Amazon****?!**

In this tutorial, you will learn how to create a React App from scratch that will serve as a basic Amazon Clone with chat capabilities right on the product page using some of CometChat’s features and components with easy steps to follow along!

On the product page, you will have a button to start a chat with the seller. If you are the seller, all chatting requests will reach your inbox, where you can help customers resolve their issues.

Perfect!

![Desktop user interaction and chat](https://paper-attachments.dropbox.com/s_4755690A05EC5E1DBF77264772959D3A2EEE4EA94B3558E84C0DDA5B31F2BB20_1615452559881_desktop.gif)

> If you prefer to jump directly into the code, you can find it [here](https://github.com/igorasilveira/marketplace-cometchat).

## Step 1 - Creating a React App

**Create React App**

Our first step should be to create the scaffold of our vanilla React app and, for that, I like to use the `create-react-app` package. So, using *npx* to not need to have the package installed globally, you can run the following command on the folder you’d like your project to life.


    npx create-react-app chat-marketplace

You now have a new folder named *chat-marketplace* that will hold all of our code and configurations.

**Install TailwindCSS**

In order to install [TailwindCSS](https://tailwindcss.com/) that we will be using to style our components, please refer to the most updated official tutorial on TailwindCSS docs related to using the *Create React App* starter, [here](https://tailwindcss.com/docs/guides/create-react-app).

After the setup, replace your `tailwind.config.js` with the following, for best results.

```javascript
    module.exports = {
      purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
      darkMode: false, // or 'media' or 'class'
      theme: {
        fontSize: {
          tiny: '0.7rem',
        },
        extend: {},
      },
      variants: {
        extend: {
          display: ['group-hover'],
        },
      },
      plugins: [],
    };
```
    
## Step 2 - Preparing Firebase Integration

The next step you should take in order to get this up and running is to set up your serverless backend. For this project, we are using Firebase to handle our user authentication and to store our application data.


> A Firebase project was already provided and configured with the environment variables if you copy the **.env.example** file in the repository and rename it by following the README instructions, but if you choose to create your own, please follow the steps below.

**Creating a Firebase Project**

If you go to Firebase’s website [here](https://firebase.google.com/), you are able to login with your Google account and create a new project. Name it something like `Chat Marketplace`. Once you are there, you are now able to add apps to your newly created project. Choose **Web App** and you are presented with your much necessary project credentials that you will need in order to run this project.

![Firebase Project Credentials](https://paper-attachments.dropbox.com/s_4755690A05EC5E1DBF77264772959D3A2EEE4EA94B3558E84C0DDA5B31F2BB20_1615762669574_Screenshot+2021-03-14+at+22.jpg)


On the root of your React project, create a new file `.env` with the following contents, replacing the values with your own project credentials.

```
    REACT_APP_FIREBASE_API_KEY=<YOUR_FIREBASE_API_KEY>
    REACT_APP_FIREBASE_AUTH_DOMAIN=<YOUR_FIREBASE_AUTH_DOMAIN>
    REACT_APP_FIREBASE_PROJECT_ID=<YOUR_FIREBASE_PROJECT_ID>
    REACT_APP_FIREBASE_STORAGE_BUCKET=<YOUR_FIREBASE_STORAGE_BUCKET>
    REACT_APP_FIREBASE_SENDER_ID=<YOUR_FIREBASE_SENDER_ID>
    REACT_APP_FIREBASE_APP_ID=<YOUR_FIREBASE_APP_ID>
```

**Enabling Authentication**

Firebase has the built-in capability of managing users authentication and state. To be able to take advantage of this we must first enable **Authentication** within our project by going to the sidebar option and enabling **Email and Password Signin** method.

![Enabling Authentication in Firebase](https://paper-attachments.dropbox.com/s_4755690A05EC5E1DBF77264772959D3A2EEE4EA94B3558E84C0DDA5B31F2BB20_1615762960417_Screenshot+2021-03-14+at+23.02.34.png)


**Initializing our Database**

For storing data we will be using [Firebase’s Firestore database](https://firebase.google.com/docs/firestore) which is a No-SQL database on the cloud. You also find it on your project’s sidebar and go through the configuration process. At the end, you should be presented with an empty database. We now need to add data to it so that our application doesn’t load empty.

You should create two **collections**, one named *categories* and another called *products*. After that, create a few category documents on the first collection adding a `*name*` and `image` attributes to each document of the collection.

For the *products* collection, each entry should have at least the following attributes: `category` (should be the name of one of the previously created categories), `description`, `id`, `image`, `price`, `title`. 

![Cloud FIrestore Schema Example](https://paper-attachments.dropbox.com/s_4755690A05EC5E1DBF77264772959D3A2EEE4EA94B3558E84C0DDA5B31F2BB20_1615763422620_Screenshot+2021-03-14+at+23.10.18.png)


We should now have everything ready regarding our serverless backend and can move on to integrating it with our React project.

For seamless integration, we will be using the [React Firebase](https://react-firebase-js.com/) package. To install it, run the following commands.


    npm i firebase && npm i @react-firebase/auth && npm i @react-firebase/firestore

The next step of the configuration is creating a `firebase.js` file on the `src` folder of your project where the configuration of your firebase app will be constructed and later used.

```javascript
    const firebaseConfig = {
      apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
      authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
      projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
      storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
      messagingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID,
      appId: process.env.REACT_APP_FIREBASE_APP_ID,
    };
    export { firebaseConfig };
```


## Step 3 - Preparing CometChat Integration

**Get your keys**

As you may know by now, we will be using the amazing real-time chat solutions provided by [CometChat](https://www.cometchat.com/).

Let’s start by creating a CometChat account by heading to their [signup page](https://app.cometchat.com/signup). After registering, you will land on your new CometChat dashboard and you can now create an App.

![CometChat Dashboard](https://paper-attachments.dropbox.com/s_4755690A05EC5E1DBF77264772959D3A2EEE4EA94B3558E84C0DDA5B31F2BB20_1615765051029_Screenshot+2021-03-14+at+23.jpg)


Once you create your app and select it, you will find the necessary configuration information right at the top of your page. These are the `appId`, `authKey` and `region`.


![CometChat App Page](https://paper-attachments.dropbox.com/s_4755690A05EC5E1DBF77264772959D3A2EEE4EA94B3558E84C0DDA5B31F2BB20_1615765290481_Screenshot+2021-03-14+at+23+1.jpg)


Copy those value and add them in the previously created `.env` file with the variables names like below:

```
    REACT_APP_COMETCHAT_APP_ID=<YOUR_COMETCHAT_APP_ID>
    REACT_APP_COMETCHAT_REGION=<YOUR_COMETCHAT_REGION>
    REACT_APP_COMETCHAT_AUTH_KEY=<YOUR_COMETCHAT_AUTH_KEY>
```

**Install CometChat Dependencies**

To install CometChat required dependencies to your React app, run the following command.


    npm install @cometchat-pro/chat@2.2.1 --save

That is it.

**Create a Helper File**

This step is aimed at abstracting most of CometChat’s required steps in order to register, login, creating and joining groups into simple functions that can be called from anywhere within the app.

On the root of your `src` folder, create a file called `cometchat.js` and with the following contents.

```javascript
    import { CometChat } from '@cometchat-pro/chat';
    const loginCometChatUser = async (uid) => {
      try {
        const user = await CometChat.login(
          uid,
          process.env.REACT_APP_COMETCHAT_AUTH_KEY
        );
        console.log('Login Successful:', { user });
      } catch (error) {
        console.log('Login failed with exception:', { error });
      }
    };
    const logoutCometChatUser = async () => {
      try {
        await CometChat.logout();
        console.log('Logout Successful:');
      } catch (error) {
        console.log('Login failed with exception:', { error });
      }
    };
    const registerCometChatUser = async (name, uid) => {
      var user = new CometChat.User(uid);
      user.setName(name);
      try {
        const createdUser = await CometChat.createUser(
          user,
          process.env.REACT_APP_COMETCHAT_AUTH_KEY
        );
        console.log('user created', createdUser);
      } catch (error) {
        console.log('Register failed with exception:', { error });
      }
    };
    const addCometChatGroup = async (GUID, name, icon, participants) => {
      let membersList = participants.map(
        (participant) =>
          new CometChat.GroupMember(
            participant,
            CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT
          )
      );
      var group = new CometChat.Group(
        GUID,
        name,
        CometChat.GROUP_TYPE.PRIVATE,
        '',
        icon
      );
      try {
        const createdGroup = await CometChat.createGroup(group);
        console.log('Group created successfully:', createdGroup);
        const response = await CometChat.addMembersToGroup(
          createdGroup.getGuid(),
          membersList,
          []
        );
        console.log('response', response);
      } catch (error) {
        console.log('Group creation failed with exception:', error);
      }
    };
    export {
      CometChat,
      loginCometChatUser,
      registerCometChatUser,
      addCometChatGroup,
      logoutCometChatUser,
    };
```

**Copy the React UI Kit**

Since we will be building our marketplace app with React, we will be taking advantage of the pre-built CometChat React UI Kit where we are given all the necessary components to make this work, without any further implementations and designs of our own!

To do that, head over to the [CometChat React UI Kit repository](https://github.com/cometchat-pro/cometchat-pro-react-ui-kit) and clone it. Move the `CometChatWorkspace` folder to your React app `src` folder and copy the repository’s dependencies to your `package.json` and run `npm install` to install them.

Now all configurations are set and we can start coding away our frontend project!


## Step 4 - Putting the Pieces Together

Now it is time to combine all of the above and to create the pages that will make our marketplace with real-time chatting capabilities.

**Create the entry point**

At the root of your `src` folder, create a `index.js` with the following:

```javascript
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { firebaseConfig } from './firebase';
    import { FirebaseAuthProvider } from '@react-firebase/auth';
    import { FirestoreProvider } from '@react-firebase/firestore';
    import firebase from 'firebase';
    import { CometChat } from '@cometchat-pro/chat';
    import './styles/index.css';
    import './styles/tailwind.css';
    import App from './App';
    const appSetting = new CometChat.AppSettingsBuilder()
      .subscribePresenceForAllUsers()
      .setRegion(process.env.REACT_APP_COMETCHAT_REGION)
      .build();
    CometChat.init(process.env.REACT_APP_COMETCHAT_APP_ID, appSetting).then(
      () => {
        console.log('Initialization completed successfully');
        ReactDOM.render(
          <React.StrictMode>
            <FirebaseAuthProvider {...firebaseConfig} firebase={firebase}>
              <FirestoreProvider {...firebaseConfig} firebase={firebase}>
                <App />
              </FirestoreProvider>
            </FirebaseAuthProvider>
          </React.StrictMode>,
          document.getElementById('root')
        );
      },
      (error) => {
        console.log('Initialization failed with error:', error);
        // Check the reason for error and take appropriate action.
      }
    );
```

This code is responsible for initializing CometChat and setting up Firebase and providing it to the rest of the app.

**Setting up our router**

The next important step is to create our React Router that will enable us to navigate through our pages.

There should be an `App.js` file on the `src` directory with the following code:

```javascript
    import React, { useEffect } from 'react';
    import firebase from 'firebase';
    import 'firebase/auth';
    import { Route, BrowserRouter, Switch, Redirect } from 'react-router-dom';
    import IndexPage from './pages';
    import CategoryPage from './pages/category';
    import InboxPage from './pages/inbox';
    import LoginPage from './pages/login';
    import LogoutPage from './pages/logout';
    import NewProductPage from './pages/newProduct';
    import ProductPage from './pages/product';
    import RegisterPage from './pages/register';
    function App() {
      useEffect(() => {
        firebase.auth().onAuthStateChanged((user) => {
          if (user) {
            // store the user on local storage
            localStorage.setItem('userUID', user.uid);
          } else {
            // removes the user from local storage on logOut
            localStorage.removeItem('userUID');
          }
        });
      }, []);
      return (
        <>
          <BrowserRouter>
            <Switch>
              <Route exact path="/">
                <IndexPage />
              </Route>
              <Route path="/category/:name">
                <CategoryPage />
              </Route>
              <PrivateRoute path="/inbox">
                <InboxPage />
              </PrivateRoute>
              <PrivateRoute path="/product/new">
                <NewProductPage />
              </PrivateRoute>
              <Route path="/product/:id">
                <ProductPage />
              </Route>
              <Route path="/login">
                <LoginPage />
              </Route>
              <Route path="/logout">
                <LogoutPage />
              </Route>
              <Route path="/register">
                <RegisterPage />
              </Route>
              <Route path="*">
                <IndexPage />
              </Route>
            </Switch>
          </BrowserRouter>
        </>
      );
    }
    function PrivateRoute({ children, ...rest }) {
      return (
        <Route
          {...rest}
          render={({ location }) =>
            localStorage.getItem('userUID') ? (
              children
            ) : (
              <Redirect
                to={{
                  pathname: '/login',
                  state: { from: location },
                }}
              />
            )
          }
        />
      );
    }
    export default App;
```

You now added the capabilities of moving through pages and protecting routes from unauthenticated users by checking if they are logged in prior to rendering the corresponding component!

**Create a Layout Wrapper**

This is a nice practice I like to have in order to keep code duplication to a minimum, and ease of development. Create a High-Order-Component that you can use to wrap around the render of each page, taking care of common elements like the footer and navigation bar, as well as providing common and necessary props to each page.

On the `src` directory, create a new `wrappers` folder and in it, a `layout.js` file with the following content: 

```javascript
    import Navbar from "../components/Navbar";
    import Footer from "../components/Footer";
    const withLayout = (BaseComponent, { bgWhite = false } = {}) => (props) => {
      return (
        <>
          <Navbar />
          <main className={`px-4 bg-${bgWhite ? "white" : "gray-200"}  pb-4 `}>
            <BaseComponent {...props} />
          </main>
          <Footer />
        </>
      );
    };
    export { withLayout };
```

Now, any component can be wrapper with `withLayout(Component)` and will be rendered within the same conditions.

**Creating our Components**

On the `src` directory, create a `components` folder where all of our components will exist.

Let’s create our navigation bar first. Create a `Navbar.js` file with this content:

```javascript
    import { FirebaseAuthConsumer } from '@react-firebase/auth';
    import { FirestoreCollection } from '@react-firebase/firestore';
    import React from 'react';
    import { Link } from 'react-router-dom';
    export default function Navbar() {
      return (
        <nav className="w-full flex flex-col relative z-10">
          <div className="bg-gray-900 w-full flex justify-between items-center mx-auto px-3 py-1">
            {/* <!-- logo --> */}
            <div className="inline-flex">
              <a className="_o6689fn" href="/">
                <img src="/logo-white.png" className="w-24" alt="Logo"></img>
              </a>
            </div>
            {/* <!-- end logo --> */}
            {/* <!-- start delivery location --> */}
            <button type="button">
              <div className="hidden sm:block flex mx-1">
                <div className="flex justify-center items-center">
                  <div className="h-6 w-6 flex justify-center items-center">
                    <svg
                      viewBox="0 0 12 12"
                      xmlns="http://www.w3.org/2000/svg"
                      aria-hidden="true"
                      role="presentation"
                      focusable="false"
                      className="h-2 w-2 overflow-visible"
                      style={{
                        fill: 'none',
                        stroke: '#ffffff',
                        strokeWidth: 1.33333,
                      }}
                    >
                      <g fill="none">
                        <path d="M10,1.375c-3.17,0-5.75,2.548-5.75,5.682c0,6.685,5.259,11.276,5.483,11.469c0.152,0.132,0.382,0.132,0.534,0c0.224-0.193,5.481-4.784,5.483-11.469C15.75,3.923,13.171,1.375,10,1.375 M10,17.653c-1.064-1.024-4.929-5.127-4.929-10.596c0-2.68,2.212-4.861,4.929-4.861s4.929,2.181,4.929,4.861C14.927,12.518,11.063,16.627,10,17.653 M10,3.839c-1.815,0-3.286,1.47-3.286,3.286s1.47,3.286,3.286,3.286s3.286-1.47,3.286-3.286S11.815,3.839,10,3.839 M10,9.589c-1.359,0-2.464-1.105-2.464-2.464S8.641,4.661,10,4.661s2.464,1.105,2.464,2.464S11.359,9.589,10,9.589"></path>
                      </g>
                    </svg>
                  </div>
                  <div className="flex flex-col text-base leading-tight text-left">
                    <p className="text-gray-400 font-bold tracking-tight">
                      Deliver to
                    </p>
                    <p className="text-white font-bold">Portugal</p>
                  </div>
                </div>
              </div>
            </button>
            {/* <!-- end delivery location --> */}
            {/* <!-- search bar --> */}
            <div className="sm:block flex flex-grow mx-2">
              <div className="flex items-center flex-grow max-w-full">
                <form
                  className="flex items-center flex-grow pl-2 relative rounded-sm bg-white"
                  type="button"
                >
                  <input
                    className="flex-grow relative text-sm"
                    placeholder="Search anything..."
                  ></input>
                  <div className="flex items-center justify-center relative rounded-r-sm bg-yellow-400 p-2">
                    <div className="h-3 w-3">
                      <svg
                        viewBox="0 0 20 20"
                        xmlns="http://www.w3.org/2000/svg"
                        aria-hidden="true"
                        role="presentation"
                        focusable="false"
                        className="h-2 w-2 overflow-visible"
                        style={{
                          fill: 'none',
                          stroke: 'currentcolor',
                          strokeWidth: 3.33333,
                        }}
                      >
                        <g fill="none">
                          <path d="m13 24c6.0751322 0 11-4.9248678 11-11 0-6.07513225-4.9248678-11-11-11-6.07513225 0-11 4.92486775-11 11 0 6.0751322 4.92486775 11 11 11zm8-3 9 9"></path>
                        </g>
                      </svg>
                    </div>
                  </div>
                </form>
              </div>
            </div>
            {/* <!-- end search bar --> */}
            {/* <!-- login --> */}
            <div className="sm:block flex mx-2 mr-4">
              <div className="flex justify-center items-center">
                <div className="flex flex-col text-base leading-tight text-left group inline-block relative">
                  <p className="text-white inline-flex">Hello,</p>
                  <FirebaseAuthConsumer>
                    {({ isSignedIn }) => (
                      <ul className="absolute hidden text-gray-700 group-hover:block rounded bg-white shadow mt-16 md:mt-7 font-bold text-md">
                        {!isSignedIn && (
                          <li className="">
                            <Link
                              className="rounded-t hover:bg-gray-200 py-2 px-4 block whitespace-no-wrap"
                              to="/login"
                            >
                              Sign In
                            </Link>
                          </li>
                        )}
                        {isSignedIn && (
                          <>
                            <li className="">
                              <Link
                                className="rounded-t hover:bg-gray-200 py-2 px-4 block whitespace-no-wrap"
                                to="/logout"
                              >
                                Sign Out
                              </Link>
                            </li>
                            <li className="">
                              <Link
                                className="rounded-t hover:bg-gray-200 py-2 px-4 block whitespace-no-wrap"
                                to="/product/new"
                              >
                                New Product
                              </Link>
                            </li>
                            <li className="block md:hidden">
                              <Link
                                className="rounded-t hover:bg-gray-200 py-2 px-4 block whitespace-no-wrap"
                                to="/inbox"
                              >
                                Inbox
                              </Link>
                            </li>
                          </>
                        )}
                      </ul>
                    )}
                  </FirebaseAuthConsumer>
                  <p className="text-white font-bold">Account & Lists</p>
                </div>
              </div>
            </div>
            {/* <!-- end login --> */}
            {/* <!-- start cart --> */}
            <Link to="/inbox">
              <button type="button">
                <div className="hidden sm:block flex mx-1">
                  <div className="flex justify-center items-end">
                    <div className="h-8 w-8 flex justify-center items-end">
                      <img
                        src="/inbox.png"
                        width="24"
                        height="24"
                        alt="Inbox Icon"
                      ></img>
                    </div>
                    <p className="text-white font-bold text-base pb-1">Inbox</p>
                  </div>
                </div>
              </button>
            </Link>
            {/* <!-- end cart --> */}
          </div>
          <div className="hidden md:block bg-gray-800 w-full flex justify-start items-center mx-auto px-2 py-2">
            <div className="text-white text-base leading-4">
              <ul className="flex">
                <FirestoreCollection path="/categories" limit={4}>
                  {({ isLoading, value }) => {
                    return isLoading ? (
                      <li>Loading</li>
                    ) : (
                      React.Children.toArray(
                        value.map((category) => (
                          <li className="capitalize mr-2">
                            <Link to={`/category/${category.name}`}>
                              {category.name}
                            </Link>
                          </li>
                        ))
                      )
                    );
                  }}
                </FirestoreCollection>
              </ul>
            </div>
          </div>
        </nav>
      );
    }
```

Next, we are creating the footer. The same as before, create a `Footer.js` file with these contents:

```javascript
    import React from 'react';
    export default function Footer() {
      return (
        <footer className="w-full flex flex-col relative">
          <div className="bg-gray-700 w-full flex justify-center items-center mx-auto px-2 py-1 md:py-2">
            <a href="#" className="text-white text-base leading-4 text-center">
              Back to top
            </a>
          </div>
          <div className="bg-gray-800 w-full flex flex-col text-center md:text-left md:flex-row justify-center md:justify-between items-center md:items-start mx-auto px-2 md:px-48 lg:px-96 py-4 md:py-10">
            <section className="my-2 md:my-0">
              <h5 className="font-bold text-white text-base">Get to Know Us</h5>
              <ul className="text-gray-200 text-base">
                <li className="leading-5">
                  <a href="#">Careers</a>
                </li>
                <li className="leading-5">
                  <a href="#">Blog</a>
                </li>
                <li className="leading-5">
                  <a href="#">About Amazon</a>
                </li>
                <li className="leading-5">
                  <a href="#">Sustainability</a>
                </li>
                <li className="leading-5">
                  <a href="#">Investor Relations</a>
                </li>
                <li className="leading-5">
                  <a href="#">Amazon Devices</a>
                </li>
                <li className="leading-5">
                  <a href="#">Amazon Tours</a>
                </li>
              </ul>
            </section>
            <section className="my-2 md:my-0">
              <h5 className="font-bold text-white text-base">Make Money with Us</h5>
              <ul className="text-gray-200 text-base">
                <li className="leading-5">
                  <a href="#">Sell products on Amazon</a>
                </li>
                <li className="leading-5">
                  <a href="#">Sell apps on Amazon</a>
                </li>
                <li className="leading-5">
                  <a href="#">Become an Affiliate</a>
                </li>
                <li className="leading-5">
                  <a href="#">Advertise Your Products</a>
                </li>
                <li className="leading-5">
                  <a href="#">Self-publish with Us</a>
                </li>
                <li className="leading-5">
                  <a href="#">Host an Amazon Hub</a>
                </li>
              </ul>
            </section>
            <section className="my-2 md:my-0">
              <h5 className="font-bold text-white text-base">
                Amazon Payment Products
              </h5>
              <ul className="text-gray-200 text-base">
                <li className="leading-5">
                  <a href="#">Amazon Business Card</a>
                </li>
                <li className="leading-5">
                  <a href="#">Shop With Points</a>
                </li>
                <li className="leading-5">
                  <a href="#">Reload Your Balance</a>
                </li>
                <li className="leading-5">
                  <a href="#">Amazon Currency Converter</a>
                </li>
              </ul>
            </section>
            <section className="my-2 md:my-0">
              <h5 className="font-bold text-white text-base">Let Us Help You</h5>
              <ul className="text-gray-200 text-base">
                <li className="leading-5">
                  <a href="#">Amazon and COVID-19</a>
                </li>
                <li className="leading-5">
                  <a href="#">Your Account</a>
                </li>
                <li className="leading-5">
                  <a href="#">Your Orders</a>
                </li>
                <li className="leading-5">
                  <a href="#">Shipping Rates and Policies</a>
                </li>
                <li className="leading-5">
                  <a href="#">Returns and Replacements</a>
                </li>
                <li className="leading-5">
                  <a href="#">Manage Your Content and Devices</a>
                </li>
                <li className="leading-5">
                  <a href="#">Amazon Assistant</a>
                </li>
                <li className="leading-5">
                  <a href="#">Help</a>
                </li>
              </ul>
            </section>
          </div>
          <div className="bg-gray-800 w-full flex justify-center items-center mx-auto py-4 lg:py-6 border-t border-gray-700">
            <div className="inline-flex">
              <a className="_o6689fn" href="/">
                <img src="/logo-white.png" className="w-24" alt="Logo"></img>
              </a>
            </div>
          </div>
          <div className="bg-black w-full flex justify-center items-center mx-auto py-2 border-t border-gray-700">
            <ul className="text-white flex text-base">
              <li>
                <a href="#" className="font-bold mr-2">
                  Conditions of Use
                </a>
              </li>
              <li>
                <a href="#" className="font-bold mr-2">
                  Privacy Notice
                </a>
              </li>
              <li>
                <a href="#" className="font-bold mr-2">
                  Interest-Based Ads
                </a>
              </li>
              <li>
                <span className="text-gray-400">
                  &copy; 1996-2021, Amazon.com, Inc. or its affiliates
                </span>
              </li>
            </ul>
          </div>
        </footer>
      );
    }
```

Now our most common components which are part of our `Layout` component are finished and we can move on to your specific on-page components.

Let’s start with our category cards that feature on the main page. Create a `CategoryCard.js` and add the following code:

```javascript
    import React from 'react';
    import { Link } from 'react-router-dom';
    export default function CategoryCard({ category: { name, image } }) {
      return (
        <div className="bg-white w-full h-full p-4">
          <p className="font-bold capitalize">{name}</p>
          <Link to={`/category/${name}`} className="text-base text-blue-500">
            <img
              src={image}
              alt={name}
              className="w-48 h-48 my-4 lg:my-6 mx-auto"
            />
            <p>Shop now</p>
          </Link>
        </div>
      );
    }
```


    Still for the main page, let’s create a product slider which features horizontal scrolling! Create a `ProductSlider.js` with the following:

```javascript
    import React from 'react';
    import { Link } from 'react-router-dom';
    export default function ProductSlider({ title, products }) {
      return (
        <div className="bg-white p-4">
          <span className="font-bold text-md text-gray-600 mr-4">{title}</span>
          <a href="#" className="text-base text-blue-500">
            Shop now
          </a>
          <div
            style={{
              gridTemplateColumns: `repeat(${products.length}, calc(20% - 1rem * ${
                2 / window.innerWidth
              }))`,
            }}
            className={`grid gap-2 md:gap-4 grid-rows-1 overflow-x-scroll whitespace-nowrap my-4`}
          >
            {React.Children.toArray(
              products.map((product) => (
                <Link to={`/product/${product.id || 1}`}>
                  <img
                    src={product.image}
                    alt={product.title}
                    className="h-24 md:w-24 md:my-3"
                  />
                </Link>
              ))
            )}
          </div>
        </div>
      );
    }
```

When we are on a specific category page, we have multiple products being displayed on a very structured manner. Let’s create that specific individuallized component, `ProductCard`. Create that file and add the code:

```javascript
    import React from 'react';
    import { Link } from 'react-router-dom';
    export default function ProductCard({
      product: { image, title, price, id },
      bestSeller = false,
    }) {
      return (
        <Link to={`/product/${id}`}>
          <div className="p-2 flex flex-col bg-white">
            {bestSeller && (
              <div className="bg-yellow-600 py-1 px-2 bo self-start text-base font-bold text-white">
                Best Seller
              </div>
            )}
            <img src={image} className="h-32 w-32 my-4"></img>
            <p className="text-base">{title}</p>
            <div className="h-2 w-2 flex justify-center items-center my-2">
              <svg
                viewBox="0 0 16 16"
                xmlns="http://www.w3.org/2000/svg"
                aria-hidden="true"
                role="presentation"
                focusable="false"
                className="h-2 w-2 overflow-visible"
                style={{
                  fill: '#FF9900',
                  stroke: '#bd7100',
                  strokeWidth: 1,
                }}
              >
                <path d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218" />
                <path
                  transform="translate(21)"
                  d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                />
                <path
                  transform="translate(42)"
                  d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                />
                <path
                  transform="translate(64)"
                  d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                />
                <path
                  transform="translate(86)"
                  d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                  fill="#f9de8c"
                />
                <path
                  transform="translate(86)"
                  d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792"
                />
              </svg>
            </div>
            <span className="text-sm leading-1">{price}€</span>
            <p className="text-base">
              Arrives: <span className="font-bold">Tomorrow</span>
            </p>
          </div>
        </Link>
      );
    }
```

All that is left, component-wise, is the side-filter that we normally see on Amazon’s product search pages. Ours is entirely mocked with no real function, but it serves it purpose. Add a new `SideFilter.js` file and paste the contents:

```javascript
    import React from 'react';
    import { Link } from 'react-router-dom';
    export default function ProductCard({
      product: { image, title, price, id },
      bestSeller = false,
    }) {
      return (
        <Link to={`/product/${id}`}>
          <div className="p-2 flex flex-col bg-white">
            {bestSeller && (
              <div className="bg-yellow-600 py-1 px-2 bo self-start text-base font-bold text-white">
                Best Seller
              </div>
            )}
            <img src={image} className="h-32 w-32 my-4"></img>
            <p className="text-base">{title}</p>
            <div className="h-2 w-2 flex justify-center items-center my-2">
              <svg
                viewBox="0 0 16 16"
                xmlns="http://www.w3.org/2000/svg"
                aria-hidden="true"
                role="presentation"
                focusable="false"
                className="h-2 w-2 overflow-visible"
                style={{
                  fill: '#FF9900',
                  stroke: '#bd7100',
                  strokeWidth: 1,
                }}
              >
                <path d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218" />
                <path
                  transform="translate(21)"
                  d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                />
                <path
                  transform="translate(42)"
                  d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                />
                <path
                  transform="translate(64)"
                  d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                />
                <path
                  transform="translate(86)"
                  d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                  fill="#f9de8c"
                />
                <path
                  transform="translate(86)"
                  d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792"
                />
              </svg>
            </div>
            <span className="text-sm leading-1">{price}€</span>
            <p className="text-base">
              Arrives: <span className="font-bold">Tomorrow</span>
            </p>
          </div>
        </Link>
      );
    }
```

All done now. Let’s create the pages!

**Creating the Pages**

We already have a handful of components, but nowhere to display them since our router can’t even find the pages it needs to properly manage navigations, so let’s fix that. Still on the `src` folder, create a new directory to hold our pages. Call it `pages`.

Starting with Login and Register pages, create two files named `login.js` and `register.js` and add the following code to each, respectively.

 **login.js**

```javascript
    import React, { useReducer, useState } from 'react';
    import { Link, useHistory } from 'react-router-dom';
    import firebase from 'firebase/app';
    import 'firebase/auth';
    import { loginCometChatUser } from '../cometchat';
    const initialState = {
      email: '',
      password: '',
    };
    const reducer = (state, action) => {
      switch (action.type) {
        case 'email':
          return { ...state, email: action.payload };
        case 'password':
          return { ...state, password: action.payload };
        default:
          throw new Error();
      }
    };
    export default function LoginPage() {
      const [state, dispatch] = useReducer(reducer, initialState);
      const [error, setError] = useState('');
      let history = useHistory();
      const handleOnChange = (evt) => {
        const { target } = evt;
        dispatch({
          type: target.name,
          payload: target.value,
        });
      };
      const loginUser = (evt) => {
        evt.preventDefault();
        firebase
          .auth()
          .signInWithEmailAndPassword(state.email, state.password)
          .then((doc) => {
            loginCometChatUser(doc.user.uid);
            history.push('/');
          })
          .catch((err) => {
            setError(err.message);
            console.log(`Unable to login: ${err.message}`);
          });
      };
      return (
        <div>
          <div className="flex flex-col justify-center items-center mx-auto px-2 py-2 border-gray-700 w-full md:w-96">
            <div className="inline-flex">
              <Link to="/">
                <img src="/logo-black.png" className="w-24" alt="Logo"></img>
              </Link>
            </div>
            <form
              className="border-gray-300 border rounded-sm my-4 p-4"
              onSubmit={loginUser}
            >
              <h1 className="font-bold">Sign-In</h1>
              {error && (
                <p className="text-red-500 font-bold text-base py-2 ">{error}</p>
              )}
              <label htmlFor="email" className="font-bold text-base md:ml-1">
                Email
              </label>
              <input
                id="email"
                name="email"
                type="email"
                autoComplete="email"
                required
                onChange={handleOnChange}
                value={state.email}
                className="appearance-none rounded-sm relative block w-full p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 text-base"
                placeholder="Email"
              />
              <label htmlFor="password" className="font-bold text-base md:ml-1">
                Password
              </label>
              <input
                id="password"
                name="password"
                type="password"
                autoComplete="password"
                required
                onChange={handleOnChange}
                value={state.password}
                className="appearance-none rounded-sm relative block w-full p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 text-base"
                placeholder="Password"
              />
              <button
                type="submit"
                className="bg-gradient-to-t from-yellow-300 to-yellow-100 text-base p-1 w-full rounded-sm my-3 border border-gray-500"
              >
                Continue
              </button>
              <p className="text-base tracking-none">
                By continuing, you agree to Amazon's{' '}
                <a href="#" className="text-blue-500">
                  Conditions of Use
                </a>{' '}
                and{' '}
                <a href="#" className="text-blue-500">
                  Privacy Notice
                </a>
                .
              </p>
            </form>
            <p className="text-center text-base text-gray-500">New to Amazon?</p>
            <button
              type="submit"
              className="w-full bg-gradient-to-t from-gray-200 to-white text-base p-1 rounded-sm my-3 border border-gray-500"
            >
              <Link to="/register">Create your Amazon account</Link>
            </button>
          </div>
        </div>
      );
    }
```

 **register.js**

```javascript
    import React, { useReducer, useState } from 'react';
    import { Link, useHistory } from 'react-router-dom';
    import firebase from 'firebase/app';
    import 'firebase/auth';
    import { loginCometChatUser, registerCometChatUser } from '../cometchat';
    const initialState = {
      name: '',
      email: '',
      password: '',
      confirmPassword: '',
    };
    const reducer = (state, action) => {
      switch (action.type) {
        case 'name':
          return { ...state, name: action.payload };
        case 'email':
          return { ...state, email: action.payload };
        case 'password':
          return { ...state, password: action.payload };
        case 'confirmPassword':
          return { ...state, confirmPassword: action.payload };
        default:
          throw new Error();
      }
    };
    export default function RegisterPage() {
      const [state, dispatch] = useReducer(reducer, initialState);
      const [error, setError] = useState('');
      const history = useHistory();
      const handleOnChange = (evt) => {
        const { target } = evt;
        dispatch({
          type: target.name,
          payload: target.value,
        });
      };
      const registerUser = (evt) => {
        evt.preventDefault();
        if (state.password !== state.confirmPassword) {
          setError('Error: Passwords do not match.');
          return;
        }
        firebase
          .auth()
          .createUserWithEmailAndPassword(state.email, state.password)
          .then(async (doc) => {
            await registerCometChatUser(state.name, doc.user.uid);
            await loginCometChatUser(doc.user.uid);
            history.push('/');
          })
          .catch((err) => {
            setError(err.message);
            console.log(`Unable to register user: ${err.message}`);
          });
      };
      return (
        <div>
          <div className="flex flex-col justify-center items-center mx-auto px-2 py-2 border-gray-700 w-full md:w-96">
            <div className="inline-flex">
              <Link to="/">
                <img src="/logo-black.png" className="w-24" alt="Logo"></img>
              </Link>
            </div>
            <form
              className="border-gray-300 border rounded-sm my-4 p-4"
              onSubmit={registerUser}
            >
              <h1 className="font-bold">Create Account</h1>
              {error && (
                <p className="text-red-500 font-bold text-base py-2 ">{error}</p>
              )}
              <label htmlFor="name" className="font-bold text-base md:ml-1">
                Name
              </label>
              <input
                id="name"
                name="name"
                type="name"
                autoComplete="name"
                required
                onChange={handleOnChange}
                value={state.name}
                className="appearance-none rounded-sm relative block w-full p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-base"
                placeholder="Name"
                minLength={3}
              />
              <label htmlFor="email" className="font-bold text-base md:ml-1">
                Email
              </label>
              <input
                id="email"
                name="email"
                type="email"
                autoComplete="email"
                required
                onChange={handleOnChange}
                value={state.email}
                className="appearance-none rounded-sm relative block w-full p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-base"
                placeholder="Email"
              />
              <label htmlFor="password" className="font-bold text-base md:ml-1">
                Password
              </label>
              <input
                id="password"
                name="password"
                type="password"
                autoComplete="password"
                required
                onChange={handleOnChange}
                value={state.password}
                className="appearance-none rounded-sm relative block w-full p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-base"
                placeholder="Password"
                minLength={6}
              />
              <label htmlFor="password" className="font-bold text-base md:ml-1">
                Re-Enter Password
              </label>
              <input
                id="confirmPassword"
                name="confirmPassword"
                type="password"
                autoComplete="password"
                required
                onChange={handleOnChange}
                value={state.confirmPassword}
                className="appearance-none rounded-sm relative block w-full p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-base"
                placeholder="Re-Enter Password"
                minLength={6}
              />
              <button
                type="submit"
                className="bg-gradient-to-t from-yellow-300 to-yellow-100 text-base p-1 w-full rounded-sm my-3 border border-gray-500"
              >
                Create your Amazon account
              </button>
              <p className="text-base tracking-none">
                By continuing, you agree to Amazon's{' '}
                <a href="#" className="text-blue-500">
                  Conditions of Use
                </a>{' '}
                and{' '}
                <a href="#" className="text-blue-500">
                  Privacy Notice
                </a>
                .
              </p>
              <div className="w-1/2 mx-auto mt-4 border-t-2 border-gray-100"></div>
              <p className="text-base">
                Alread have an account?{' '}
                <Link to="login" className="text-blue-500">
                  Sign In
                </Link>
              </p>
            </form>
          </div>
        </div>
      );
    }
```

Now going onto the main pages, the index page is the first time we resort to our Firestore collections in order to render it, since it will display both category and product lists! Create a new `index.js` file and paste its contents:

```javascript
    import { FirestoreCollection } from '@react-firebase/firestore';
    import React from 'react';
    import CategoryCard from '../components/CategoryCard';
    import ProductSlider from '../components/ProductSlider';
    import { withLayout } from '../wrappers/layout';
    const IndexPage = () => {
      return (
        <div
          style={{
            backgroundImage: `url("/hero.jpg")`,
          }}
          className="w-full h-full pt-10 md:pt-32 bg-no-repeat bg-contain"
        >
          <div className="mx-4">
            <section className="grid grid-cols-1 md:grid-cols-4 gap-4 grid-flow-row auto-rows-max">
              <FirestoreCollection path="/categories">
                {({ isLoading, value }) => {
                  return isLoading ? (
                    <h3>Loading</h3>
                  ) : (
                    React.Children.toArray(
                      value.map((category) => <CategoryCard category={category} />)
                    )
                  );
                }}
              </FirestoreCollection>
            </section>
            <section className="mt-4">
              <FirestoreCollection path="/products" limit={12}>
                {({ isLoading, value }) => {
                  return isLoading ? (
                    <h3>Loading</h3>
                  ) : (
                    <ProductSlider products={value} title="Recent Products" />
                  );
                }}
              </FirestoreCollection>
            </section>
          </div>
        </div>
      );
    };
    export default withLayout(IndexPage);
```

The rest of the pages are pretty straightforward. We will be creating specific pages for *category*, *product*, *new product*, and a simple *logout.*

 **category.js**

```javascript
    import { FirestoreCollection } from '@react-firebase/firestore';
    import React from 'react';
    import { useParams } from 'react-router';
    import ProductCard from '../components/ProductCard';
    import SideFilter from '../components/SideFilter';
    import { withLayout } from '../wrappers/layout';
    const CategoryPage = () => {
      const { name } = useParams();
      return (
        <div className="grid grid-cols-3 md:grid-cols-9 py-4">
          <div className="col-span-1">
            <SideFilter />
          </div>
          <div className="flex-grow w-full ml-4 col-span-2 md:col-span-8">
            <div className="text-black border-b border-gray-300 pb-2">
              <h1 className="capitalize font-bold">{name}</h1>
              <h3 className="capitalize text-base">Shop {name}</h3>
            </div>
            <section className="grid grid-cols-1 md:grid-cols-3 gap-8 my-4">
              <FirestoreCollection
                path="/products"
                limit={12}
                where={{
                  field: 'category',
                  operator: '==',
                  value: name,
                }}
              >
                {({ isLoading, value }) => {
                  return isLoading ? (
                    <h3>Loading</h3>
                  ) : (
                    React.Children.toArray(
                      value.map((product, index) => (
                        <div className="border-b">
                          <ProductCard product={product} bestSeller={index === 0} />
                        </div>
                      ))
                    )
                  );
                }}
              </FirestoreCollection>
            </section>
          </div>
        </div>
      );
    };
    export default withLayout(CategoryPage, { bgWhite: true });
``` 

 **product.js**

```javascript
    import { IfFirebaseAuthedAnd } from '@react-firebase/auth';
    import { FirestoreCollection } from '@react-firebase/firestore';
    import React from 'react';
    import { useHistory, useParams } from 'react-router';
    import { addCometChatGroup } from '../cometchat';
    import { withLayout } from '../wrappers/layout';
    const ProductPage = () => {
      const { id } = useParams();
      const history = useHistory();
      const createProductChatGroup = async (
        uid,
        ownerUID,
        title,
        image,
        productId
      ) => {
        const GUID = `${uid}-${ownerUID}-${productId}`;
        try {
          await addCometChatGroup(GUID, title, image, [uid, ownerUID]);
          history.push('/inbox');
        } catch (error) {
          console.log('Group creation failed with exception:', error);
        }
      };
      return (
        <FirestoreCollection
          limit={1}
          path="/products"
          where={{
            field: 'id',
            operator: '==',
            value: id,
          }}
        >
          {({ isLoading, value }) => {
            if (isLoading) {
              return <p>Loading...</p>;
            }
            const { image, title, price, description, ownerUID, id } = value[0];
            return (
              <div className="flex flex-col px-2 md:px-10">
                <div className="block md:grid grid-cols-11 py-4 gap-4 md:gap-6">
                  <div className="col-span-5 bg-red-200">
                    <img src={image} className="w-full" alt="Product"></img>
                  </div>
                  <div className="col-span-4">
                    <div className="">
                      <p className="font-bold text-lg">{title}</p>
                      <div className="h-2 flex flew-row justify-start items-center my-2">
                        <svg
                          viewBox="0 0 120 16"
                          xmlns="http://www.w3.org/2000/svg"
                          aria-hidden="true"
                          role="presentation"
                          focusable="false"
                          className="h-2 overflow-visible"
                          style={{
                            fill: '#FF9900',
                            stroke: '#bd7100',
                            strokeWidth: 1,
                          }}
                        >
                          <path d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218" />
                          <path
                            transform="translate(21)"
                            d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                          />
                          <path
                            transform="translate(42)"
                            d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                          />
                          <path
                            transform="translate(64)"
                            d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                          />
                          <path
                            transform="translate(86)"
                            d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218"
                            fill="#f9de8c"
                          />
                          <path
                            transform="translate(86)"
                            d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792"
                          />
                        </svg>
                        <p className="text-blue-500 text-base">426 ratings</p>
                      </div>
                    </div>
                    <div className="border-b border-t my-2 py-2">
                      <p className="text-base text-gray-700 mb-1">
                        Price:{' '}
                        <span className="text-lg text-red-600 font-bold px-1">
                          {price}€
                        </span>
                        + Shipping fees to delivery
                      </p>
                      <p className="text-base">
                        Available at a lower price from other sellers that may not
                        offer free Prime shipping.
                      </p>
                    </div>
                    <div className="my-1 text-base">
                      <h4 className="font-bold">About this item</h4>
                      <p className="py-1">{description}</p>
                    </div>
                  </div>
                  <div className="block col-span-2 p-3 rounded border border-gray-300 w-full">
                    <p className="text-base text-gray-700 mb-1">
                      <span className="text-md text-red-600 font-bold pr-1">
                        {price}€
                      </span>
                      + Shipping fees to delivery
                    </p>
                    <div className="my-2">
                      <p className="text-gray-700 text-base py-1">
                        Arrives:{' '}
                        <span className="font-bold text-black">Tomorrow</span>
                      </p>
                      <div className="flex justify-start items-center">
                        <div className="h-4 w-4 flex justify-start items-center">
                          <svg
                            viewBox="0 0 12 12"
                            xmlns="http://www.w3.org/2000/svg"
                            aria-hidden="true"
                            role="presentation"
                            focusable="false"
                            className="h-2 w-2 overflow-visible -mt-1"
                            style={{
                              fill: 'none',
                              stroke: '#000000',
                              strokeWidth: 1,
                            }}
                          >
                            <g fill="none">
                              <path d="M10,1.375c-3.17,0-5.75,2.548-5.75,5.682c0,6.685,5.259,11.276,5.483,11.469c0.152,0.132,0.382,0.132,0.534,0c0.224-0.193,5.481-4.784,5.483-11.469C15.75,3.923,13.171,1.375,10,1.375 M10,17.653c-1.064-1.024-4.929-5.127-4.929-10.596c0-2.68,2.212-4.861,4.929-4.861s4.929,2.181,4.929,4.861C14.927,12.518,11.063,16.627,10,17.653 M10,3.839c-1.815,0-3.286,1.47-3.286,3.286s1.47,3.286,3.286,3.286s3.286-1.47,3.286-3.286S11.815,3.839,10,3.839 M10,9.589c-1.359,0-2.464-1.105-2.464-2.464S8.641,4.661,10,4.661s2.464,1.105,2.464,2.464S11.359,9.589,10,9.589"></path>
                            </g>
                          </svg>
                        </div>
                        <p className="text-blue-400  text-base">
                          Deliver to Portugal
                        </p>
                      </div>
                    </div>
                    <p className="font-bold text-green-600 my-2">In Stock.</p>
                    <select className="text-base bg-gradient-to-t from-gray-300 to-gray-100 rounded-lg border border-gray-400 shadow">
                      <option value="1">1</option>
                      <option value="2">2</option>
                      <option value="3">3</option>
                      <option value="4">4</option>
                      <option value="5">5</option>
                      <option value="6">6</option>
                      <option value="7">7</option>
                      <option value="8">8</option>
                      <option value="9">9</option>
                      <option value="10">10</option>
                    </select>
                    <button
                      type="submit"
                      className="bg-gradient-to-t from-yellow-300 to-yellow-100 text-base p-1 w-full rounded-sm my-2 border border-gray-500"
                    >
                      Add to Cart
                    </button>
                    <button
                      type="submit"
                      className="bg-gradient-to-t from-yellow-600 to-yellow-400 text-base p-1 w-full rounded-sm my-2 border border-gray-500"
                    >
                      Buy now
                    </button>
                    <IfFirebaseAuthedAnd
                      filter={({ user }) => {
                        return ownerUID && user.uid !== ownerUID;
                      }}
                    >
                      {({ user }) => (
                        <button
                          className="bg-gradient-to-t from-blue-400 to-blue-200 text-base p-1 w-full my-2 rounded-sm border border-gray-500 text-white"
                          onClick={() =>
                            createProductChatGroup(
                              user.uid,
                              ownerUID,
                              title,
                              image,
                              id
                            )
                          }
                        >
                          Chat with Seller
                        </button>
                      )}
                    </IfFirebaseAuthedAnd>
                  </div>
                </div>
              </div>
            );
          }}
        </FirestoreCollection>
      );
    };
    export default withLayout(ProductPage, { bgWhite: true });
```

 **newProduct.js**

```javascript
    import React, { useReducer, useState } from 'react';
    import { Link } from 'react-router-dom';
    import firebase from 'firebase/app';
    import 'firebase/auth';
    import 'firebase/database';
    import { FirestoreCollection } from '@react-firebase/firestore';
    import { v4 as uuidv4 } from 'uuid';
    const initialState = {
      title: '',
      description: '',
      category: '',
      image: '',
      price: 1,
    };
    const reducer = (state, action) => {
      switch (action.type) {
        case 'title':
          return { ...state, title: action.payload };
        case 'description':
          return { ...state, description: action.payload };
        case 'category':
          return { ...state, category: action.payload };
        case 'image':
          return { ...state, image: action.payload };
        case 'price':
          return { ...state, price: action.payload };
        case 'reset':
          return { ...action.payload };
        default:
          throw new Error();
      }
    };
    export default function NewProductPage() {
      const [state, dispatch] = useReducer(reducer, initialState);
      const [error, setError] = useState('');
      const handleOnChange = (evt) => {
        const { target } = evt;
        dispatch({
          type: target.name,
          payload: target.value,
        });
      };
      const createProduct = (evt) => {
        evt.preventDefault();
        const currentUserUID = firebase.auth().currentUser.uid;
        firebase
          .firestore()
          .collection('/products')
          .add({
            ...state,
            ownerUID: currentUserUID,
            id: uuidv4(),
          })
          .then(() => {
            dispatch({
              type: 'reset',
              payload: initialState,
            });
          })
          .catch((err) => {
            setError(err.message);
            console.log(`Unable to login: ${err.message}`);
          });
      };
      return (
        <div className="w-full">
          <div className="flex flex-col justify-center items-center mx-auto px-2 py-2 border-gray-700 w-full md:w-96">
            <div className="inline-flex">
              <Link to="/">
                <img src="/logo-black.png" className="w-24" alt="Logo"></img>
              </Link>
            </div>
            <form
              className="border-gray-300 border rounded-sm my-4 p-4 w-full"
              onSubmit={createProduct}
            >
              <h1 className="font-bold">New Product</h1>
              {error && (
                <p className="text-red-500 font-bold text-base py-2 ">{error}</p>
              )}
              <label htmlFor="title" className="font-bold text-base ml-1">
                Title
              </label>
              <input
                id="title"
                name="title"
                type="title"
                autoComplete="title"
                required
                onChange={handleOnChange}
                value={state.title}
                className="appearance-none rounded-sm relative block w-full p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-base"
                placeholder="Title"
              />
              <label htmlFor="description" className="font-bold text-base ml-1">
                Description
              </label>
              <textarea
                id="description"
                name="description"
                autoComplete="description"
                required
                onChange={handleOnChange}
                value={state.description}
                rows={4}
                className="appearance-none rounded-sm relative block w-full p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-base"
                placeholder="Description"
              />
              <label htmlFor="image" className="font-bold text-base ml-1">
                Image URL
              </label>
              <input
                id="image"
                name="image"
                type="text"
                autoComplete="image"
                required
                onChange={handleOnChange}
                value={state.image}
                className="appearance-none rounded-sm relative block w-full p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-base"
                placeholder="https://..."
              />
              <label htmlFor="category" className="font-bold text-base ml-1">
                Category
              </label>
              <select
                id="category"
                name="category"
                required
                onChange={handleOnChange}
                value={state.category}
                className="capitalize appearance-none rounded-sm relative block w-1/2 p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-base"
              >
                <option className="capitalize" value="">
                  Please select one
                </option>
                <FirestoreCollection path="/categories">
                  {({ isLoading, value }) => {
                    return (
                      !isLoading &&
                      React.Children.toArray(
                        value.map((category) => {
                          return (
                            <option className="capitalize" value={category.name}>
                              {category.name}
                            </option>
                          );
                        })
                      )
                    );
                  }}
                </FirestoreCollection>
              </select>
              <label htmlFor="price" className="font-bold text-base ml-1">
                Price (€)
              </label>
              <input
                id="price"
                name="price"
                type="number"
                min={1}
                required
                onChange={handleOnChange}
                value={state.price}
                className="appearance-none rounded-sm relative block w-1/2 p-1 border border-gray-400 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-base"
                placeholder="Price per unit"
              />
              <button
                type="submit"
                className="bg-gradient-to-t from-yellow-300 to-yellow-100 text-base p-1 w-full rounded-sm my-3 border border-gray-500"
              >
                Continue
              </button>
              <p className="text-base tracking-none">
                By continuing, you agree to Amazon's{' '}
                <a href="#" className="text-blue-500">
                  Conditions of Use
                </a>{' '}
                and{' '}
                <a href="#" className="text-blue-500">
                  Privacy Notice
                </a>
                .
              </p>
            </form>
          </div>
        </div>
      );
    }
```

 **logout.js**

```javascript
    import React, { useEffect } from 'react';
    import { useHistory } from 'react-router-dom';
    import firebase from 'firebase/app';
    import 'firebase/auth';
    import { logoutCometChatUser } from '../cometchat';
    export default function LogoutPage() {
      let history = useHistory();
      useEffect(() => {
        firebase
          .auth()
          .signOut()
          .then(async () => {
            await logoutCometChatUser();
            history.push('/');
          });
      }, []);
      return <div></div>;
    }
```

Now comes one of the most important pages and yet, the simplest. The CometChat integration for visualization of conversations, for the ability to send and receive messages can be narrowed down to a single line of code using the CometChat React UI Kit. We integrated CometChat into its own page that we called the Inbox page. Create a new `inbox.js` file and paste this few lines:

```javascript
    import React from 'react';
    import { withLayout } from '../wrappers/layout';
    import { CometChatGroupListWithMessages } from '../CometChatWorkspace/src';
    const InboxPage = () => {
      return (
        <div className="h-screen w-full">
          <CometChatGroupListWithMessages />
        </div>
      );
    };
    export default withLayout(InboxPage);
```

And that is it, you now have a fully-fledged chat window!


## Step 5 - Seeing the Magic Happen

If everything went according to plan, you can now run the following command to start your web application locally and visit it at *localhost:3000*:


    npm run start

If it compiles the first try, all that is left now is to create some users and get them chatting with one another!

## Conclusion

Hopefully, with this tutorial, you were able to create a working marketplace web app with real-time chatting capabilities and no backend coding of any kind.

You have configured a fresh Firebase project, inserted No-SQL data into a cloud data source, authenticated users, set up a real-time chat solution with CometChat and got your users sending messages to each other in around 30 minutes or so.

Hope you find this tutorial helpful and don’t forget to check the official documentation of [CometChat](https://prodocs.cometchat.com/docs) to explore further and add more features to your app. The complete source code to this tutorial is available on [GitHub](https://github.com/igorasilveira/marketplace-cometchat).