How to Create an E-commerce Product Catalog in NextJS

Amarachi Iheanacho - Apr 5 '22 - - Dev Community

Transactions have been a universal concept as old as time. With improvements in the technologies and financial institutions governing buying and selling, we have evolved from the traditional markets of buying and selling to e-commerce websites.

What we will be building

This post will discuss building a product catalog that allows us to create, delete and display our products in a NextJS application. We do not require a custom backend server.

GitHub URL

https://github.com/Iheanacho-ai/appwrite-product-catalog

Prerequisites

To get the most out of this project, we require the following:

  • A basic understanding of CSS, JavaScript, and React.js.
  • Docker Desktop installed on the computer. Run the docker -v command to verify if we have docker desktop installed. If not, install it from here.
  • An Appwrite instance running on our computer. Check out the documentation to create a local Appwrite instance. We will use Appwrite’s powerful database service and experience to manage our catalog.

Setting up our Next.js app

Next.js is an open-source React framework that enables us to build server-side rendered static web applications.

To create our Next.js app, we navigate to our preferred directory and run the terminal command below:



    npx create-next-app@latest
    # or
    yarn create next-app


Enter fullscreen mode Exit fullscreen mode

After creating our app, we change the directory to the project and start a development server with:



    cd <name of our project>
    npm run dev


Enter fullscreen mode Exit fullscreen mode

To see our app, we go to http://localhost:3000.

Installing Tailwind CSS

Tailwind CSS is a "utility-first" CSS framework that allows us to rapidly create user interfaces for web applications.

To install Tailwind CSS in our project, we run these terminal commands.



    npm install -D tailwindcss postcss autoprefixer
    npx tailwindcss init -p


Enter fullscreen mode Exit fullscreen mode

These commands create two files in the root directory of our project, tailwind.config.js and postcss.config.js.

In our tailwind.config.js, we add the paths to all our template files with this code below.



    module.exports = {
      content: [
        "./pages/**/*.{js,ts,jsx,tsx}",
        "./components/**/*.{js,ts,jsx,tsx}",
      ],
      theme: {
        extend: {},
      },
      plugins: [],
    }


Enter fullscreen mode Exit fullscreen mode

Next, we add the tailwind directives in our styles/global.css file.



    @tailwind base;
    @tailwind components;
    @tailwind utilities;



Enter fullscreen mode Exit fullscreen mode

Installing Appwrite

Appwrite is an open-source, end-to-end, back-end server solution that allows developers to build applications faster.

To use Appwrite in our Next.js application, we install the Appwrite client-side SDK for web applications.



    npm install appwrite



Enter fullscreen mode Exit fullscreen mode

Creating a new Appwrite project

We go to localhost and create a new account to see our console.

On our console, there is a Create Project button. Click on it to start a new project.

Appwrite E-commerce Catalog Console Index

Our project dashboard appears once we have created the project. At the top of the page, there is a settings bar. Click it to access the Project ID and API Endpoint.

Appwrite E-commerce Catalog Console Settings Page

We copy the Project ID and API Endpoint, which we need to initialize the Appwrite Web SDK.

Appwrite E-commerce Catalog Settings Page

In our index.js file, we initialize a new Appwrite instance with the following.



    import {Appwrite} from "appwrite";
    import {useEffect, useState } from "react";

    const Home = () => {

        // Init our Web SDK
        const sdk = new Appwrite();
        sdk
        .setEndpoint('http://localhost/v1') // our API Endpoint
        .setProject(projectID) // our project ID
        ;

        return(
          <div>Hello World!</div>
        )
    }

    export default Home;


Enter fullscreen mode Exit fullscreen mode

Creating the collection and attributes

In the Appwrite web Console, on the left side of the dashboard, we click on Database.

Appwrite E-commerce Catalog Console Database Page

We create a collection in our database tab by clicking on the Add Collection button. This action redirects us to a Permissions page.

At the Collection Level, we want to assign a Read Access and Write Access with a role:all value. You can modify this customize roles and access to your database.

Appwrite E-commerce Catalog Console Permissions Page

On the right of the Permissions page, we copy the Collection ID, which we need to perform operations on collection’s documents.

Next, we go to our attributes tab to create the properties we want a document to have.

Appwrite E-commerce Catalog Console Attributes Page

We create a string attribute of productName, an integer attribute of productPrice, and a string attribute of productImage. We use these base attributes and could add more in the future.

Appwrite E-commerce Catalog Console Attributes Page

Creating the Product catalog.

In the index.js file, we create our product catalog page, which will be divided into two sections. The first section will contain a form to collect product information and the second section to list the products in our database.

In this section of the article, we will work on the form. To create the form styled with Tailwind CSS, we add the following code snippet in the index.js file.

https://gist.github.com/Iheanacho-ai/0e0d68b6f8d17cfeddccbfc4b25c5f72

Next, we augment the styles with the following in the global.css file.



    @tailwind base;
    @tailwind components;
    @tailwind utilities;

    .product-container{
      margin-left: 37%;
      width: 30%;
    }
    .cursor{
      cursor: pointer;
    }


Enter fullscreen mode Exit fullscreen mode

Here is what our form looks like.

Appwrite E-commerce Catalog Form

Adding form interaction with the database

Appwrite has a safety policy that allows only signed users to read and write to the database. However, it allows us to create an anonymous session, which we will use in this project.

In our index.js file, we create our anonymous user session using Appwrite's createAnonymousSession method.



    import {Appwrite} from "appwrite";
    import {useEffect, useState } from "react";

    const Home = () => {

        // Init our Web SDK
        const sdk = new Appwrite();
        sdk
        .setEndpoint('http://localhost/v1') // our API Endpoint
        .setProject(projectID) // our project ID
        ;

        //creating an anonymous Session

        const createAnonymousSession = async() => {
          try{
            await sdk.account.createAnonymousSession();
          }catch(err){
            console.log(err)
          }

        }
        useEffect(()=> {
          createAnonymousSession()
        }, [])

        return(
          <div>Hello World!</div>
        )
    }

    export default Home;



Enter fullscreen mode Exit fullscreen mode

Creating state variables to hold our form values

In the index.js file, we create state variables that will hold form input values.

In addition to the form input state variables, we will create a productList variable used later in this tutorial. This productList variable will hold the products we get from our database.




    const [productName, setProductName] = useState('');
    const [productPrice, setProductPrice] = useState('');
    const [productImage, setproductImage] = useState('');
    const [productList, setProductList] = useState([]);


Enter fullscreen mode Exit fullscreen mode

Next, in our index.js file, we pass the state variables as our input field values.

https://gist.github.com/Iheanacho-ai/51f4f3ef58ab56ef22026639a0514258

In the code block above, we do the following:

  • Pass the state variables as values to their respective input fields.
  • Use the onChange event listener to update the state variables when users type in the input fields.

Creating Appwrite database documents

In our index.js file, we create our handleProductCatalog function to add new documents to the database collection.




    //creates the documents and runs listProducts

    const handleProductCatalog = async () => {
      try{
        let promise = await sdk.database.createDocument(collectionID, 'unique()', {
          "productName" : productName,
          "productPrice": productPrice,
          "productImage": productImage
        });

        setProductName('');
        setProductPrice('');
        setproductImage('');

        alert('your job item has been successfully saved')

      }catch(error){
        console.log(error)
      }   
    }


Enter fullscreen mode Exit fullscreen mode

In the code block above, our handleProductCatalog function does the following:

  • Create a new document using Appwrite’s createDocument() function, while passing the collection ID and attribute values as parameters.
  • Alert us when we have successfully saved the document, then clears the information in the local state variables.

Next, we pass our handleProductCatalog to an onClick event listener on our button element.




    <button type= "button" className="cursor inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" onClick={handleProductCatalog}>
      Save
    </button>



Enter fullscreen mode Exit fullscreen mode

NOTE: We use a button with a type= button to override the button’s default submit behavior.

Here's how our index.js file should look.

https://gist.github.com/Iheanacho-ai/918a519813cf7fa14fa7b2f8753ac15c

For your product catalog images, you can use any image link. In this tutorial, however, we use images from Cloudinary as it is easier to apply transformations and optimize delivery.
To understand how to upload images to Cloudinary, check out the Cloudinary documentation.

Fill out the form, and go to the Documents section of our database to see our saved documents.

Appwrite E-commerce Catalog Console Documents Page

Creating our Product Listing Page

Our page displays the product information we entered in our form. With this logic, we want our handleProductCatalog function to be responsible for creating the documents to display our product.

In our index.js file, we create a listProducts function that gets called when we mount our app and when our handleProductCatalog function runs.




    //lists our products

    const listProducts = async () => {
      try {
        let response = await sdk.database.listDocuments(collectionID);
        setProductList(response.documents)
      } catch (error) {
        console.log(error)
        } 
      }

    useEffect(()=> {
        createAnonymousSession(),

    // runs list product function when our app mounts

        listProducts()
      }, [])


    const handleProductCatalog = async () => {
      try{
        let promise = await sdk.database.createDocument(collectionID, 'unique()', {
          "productName" : productName,
          "productPrice": productPrice,
          "productImage": productImage
        });

        setProductName('');
        setProductPrice('');
        setproductImage('');

        alert('your job item has been successfully saved')

    // runs our listProducts function

        listProducts()
      }catch(error){
        console.log(error)
      }  
    }



Enter fullscreen mode Exit fullscreen mode

The listProducts function uses the Appwrite listDocuments API that receives a collection ID parameter. ThelistProducts function finds the collection with that ID and updates the productList variable with the products from that collection.

Deleting products from our database

Next, in our index.js file we create a handleDelete function, to handle deletion of products we do not need anymore in our collection or database.



    const handleDelete = async (documentid) => {
      try {
        await sdk.database.deleteDocument('624098515dbd1ae68ea2', documentid);
        alert("item have been deleted successfully")
        listProducts()

      } catch (error) {
        console.log(error)
      }
    }



Enter fullscreen mode Exit fullscreen mode

The handleDelete function does the following:

  • Finds a document using its collection ID.
  • Deletes that document using Appwrite deleteDocument() function.
  • Alerts us if the item was successfully deleted.
  • Runs the listProducts function to display our updated product list.

Creating our product listing UI

Next, we display the products on our product listing page. We paste this code into our index.js file to do this.



    <div className="bg-white">
      <div className="max-w-2xl mx-auto py-16 px-4 sm:py-24 sm:px-6 lg:max-w-7xl lg:px-8">
        <h2 className="sr-only">Products</h2>
        {
          productList ? (
            <div className="grid grid-cols-1 gap-y-10 sm:grid-cols-2 gap-x-6 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
              {
                productList.map(({productName, productImage, productPrice, $id}) => (
                  <a href="#" className="group" id={$id}>
                    <div className="w-full aspect-w-1 aspect-h-1 bg-gray-200 rounded-lg overflow-hidden xl:aspect-w-7 xl:aspect-h-8">
                      <img src={productImage} alt="Tall slender porcelain bottle with natural clay textured body and cork stopper." className="w-full h-full object-center object-cover group-hover:opacity-75" />
                    </div>
                    <h3 className="mt-4 text-sm text-gray-700">{productName}</h3>
                    <p className="mt-1 text-lg font-medium text-gray-900">${productPrice}</p>
                    <button
                      type="button"
                      className="cursor inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
                      onClick={()=> handleDelete($id)}
                    >
                    Delete
                  </button>
                  </a>
                ))
              }
            </div>
          ) : null
        }
      </div>
    </div>



Enter fullscreen mode Exit fullscreen mode

In the code block above, we:

  • Check if the productList variable is not null.
  • Loop through the productList variable to render each product.
  • Destructure and pass in our productName, productPrice, productImage and $id variables.
  • Pass the handleDelete function we created to the onClick event listener of our button.

Here is what our complete index.js file looks like

https://gist.github.com/Iheanacho-ai/cbcb04211612c527a40c3642f064691d

Fill out the form to see what the product catalog looks like.

Appwrite E-commerce Catalog

Conclusion

This article discussed creating a product catalog using the Appwrite Database feature to create, retrieve and delete data on our database. This product catalog can serve as the basis for a full fledged inventory creation system for a store. Modify the documents to include more product fields.

Resources

Here are some resources that might be helpful:

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .