DEV Community

Cover image for Building an Efficient Waitlist App with Next.js and Xata
oteri
oteri

Posted on

Building an Efficient Waitlist App with Next.js and Xata

Launching a new product or application comes with many exciting moments, not just for the owner but for the larger audience to be aware of a new service.

A waitlist application is used by agencies, companies, marketing campaign websites, and many more to collect user data from a website when a user fills in their email address. This strategy serves the purpose of remarketing or reminders before the launch.

In this post, you’ll learn how to use Xata to store data by integrating it into a Next.js app, a React full-stack application framework for building user interfaces. Also, this guide will show you how to create a new database (DB) in your Xata admin workspace.

What is Xata?

From the official Xata documentation, Xata is a serverless database platform powered by PostgreSQL packed with features such as the fuzzy search, the ability to import CSV (comma-separated value), file attachments, Python and TypeScript SDK integration, and so on.

Prerequisites

To complete this tutorial, you need an Xata account. If you don’t have one, sign up for a free developer account now.

This tutorial assumes you’re familiar with running a Next app locally. Other requirements include the following:

  • Understanding of writing CSS with Tailwind CSS
  • Basic JavaScript knowledge

Demo

Try the demo application in this URL.

Installation and setup

Download the setup for the demo waitlist application from the main branch of this repository.

Open up your terminal and cd into the cloned directory, xata-with-nextjs.

    cd xata-with-nextjs
Enter fullscreen mode Exit fullscreen mode

Install the project dependencies using the package manager, npm:

npm install
Enter fullscreen mode Exit fullscreen mode

Now, let’s start the development server to preview the landing page with the command:

npm run dev
Enter fullscreen mode Exit fullscreen mode

The boilerplate code runs on port 3000 and should look something like this:

waitlist demo

Configuring Xata instance

To initialize the waitlist project, install the Xata CLI globally.

Run this command:

npm install -g @xata.io/cli
Enter fullscreen mode Exit fullscreen mode

Next, you need to authenticate the Xata CLI with your Xata account, as this will ensure your system is configured correctly for your profile.

You do not need to repeat this process once the configuration is complete with this command:

xata auth login 
Enter fullscreen mode Exit fullscreen mode

This command will open a new window for first-time users to authenticate and create a new API key for your user account.

Creating a new database

In your Xata account workspace dashboard, create a new database with a name.

waitlist DB

Navigate into the waitlist DB and create a table with a desired name. The defined columns in the table hold all the data information.

Click on the plus icon to add a new column. Select the data type Email and give the column the name, email.

add a new column

To see how the data looks with the inferred data types, click Schema on the left navigation pane of your dashboard.

schema

Note: The IDs are unique for each new record and auto-generated.

The other way to create a database is by following the process outlined in the Next.js starter guide. Make sure you run the xata init in the project directory.

Inserting a new record

Within the src directory, create a new folder, pages/api/post-info.js. Copy-paste the following code:

pages/api/post-info.js

    import { getXataClient } from "@/xata"

    const handler = async (request, response) => {
      const xata = await getXataClient()
      const { email } = request.body
      await xata.db.details.create({
        email
      })
      response.end()
    }

    export default handler
Enter fullscreen mode Exit fullscreen mode

Let’s break down the code snippets above.

First, import the getXataClient function from src/xata.js, which is present in the app upon initialization with xata init. Then, in the asynchronous handler function, pass the parameters, request, and response, and within the function, initialize getXataClient to a xata variable.

The request.body will handle the value email (the exact name in Xata DB) from the data submitted in the request body in the form input.

Next, pass in the data, email as an object in the create function.

The response.end() method will cause the webserver to stop once the data is created in the DB, meaning a successful status code, 200.

Integrating Xata into the app

In this section, if you experience this error when running the server, it is because the code needs to run on the server, not the client. That is within the app/page.js file.

Uncaught Error: You are trying to use Xata from the browser, which is potentially a non-secure environment. If you understand the security concerns, such as leaking your credentials, pass `enableBrowser: true` to the client options to remove this error.
Enter fullscreen mode Exit fullscreen mode

The Get started with Next.js and Xata guide shows you the proper process to follow.

Copy-paste the following code in the src/app/page.js to update the file:

    "use client"
    import { useState } from "react"
    import Footer from "@/components/Footer"
    import Services from "@/components/Services"
    import Image from "next/image"
    import { bigShoe1 } from "@/assets/images"

    export default function Home() {
      const [email, setEmail] = useState('')
      const [isSubmitted, setIsSubmitted] = useState(false)
      const [error, setError] = useState(null)
      const resetFormField = () => {
        setEmail('')
      }
       const submit = () => {
        fetch('/api/post-info', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            email
          }),
        })
      };
      const handleSubmit = (e) => {
        e.preventDefault()
        if (!email) {
          setError('Email is invalid')
          return
        }
        submit()
        resetFormField()
        setIsSubmitted(true)
      }
      const isValidEmail = (email) => {
        return /\S+@\S+\.\S+/.test(email);
      }
      const handleChange = (e) => {
        if (!isValidEmail(e.target.value)) {
          setError('Email is invalid');
        } else {
          setError(null)
        }
        setEmail(e.target.value)
      }
      return (
        <main>
          <section className="w-full py-8 z-10 sm:px-16 px-8 flex xl:flex-row flex-col justify-center gap-10">
          <div className="xl:w-2/5 flex flex-col justify-center items-start w-full">
            <p className="text-xl font-montserrat text-coral-red">Our summer collection</p>
            <h1 className='mt-10 font-palanquin text-8xl max-sm:text-[72px] font-bold'>
              <span className='xl:bg-white xl:whitespace-nowrap z-10 pr-10'>
                The New Arrival
              </span>
              <br />
              <span className='text-coral-red inline-block mt-3'>Nike </span> Shoes
            </h1>
            <p className='font-montserrat text-slate-gray text-lg leading-8 mt-6 mb-14 sm:max-w-sm'>
              Discover stylish Nike arrivals, quality comfort, and innovation for
              your active life.
            </p>
            {isSubmitted ? (
              <div>
                <p className="font-bold text-2xl">Well received! We will keep you updated.</p>
              </div>) : (
              <form className="w-full flex items-center max-sm:flex-col gap-5 p-2.5 sm:border sm:border-slate-gray rounded-full" onSubmit={handleSubmit} id="joinwaitlist">
              <input type="email" name="email" id="email" placeholder="Enter your email address" className="input" value={email} onChange={handleChange} />
                <div className="flex max-sm:justify-end items-center max-sm:w-full">
                <button className="w-full bg-coral-red rounded-full text-white border-coral-red px-7 py-4" type="submit">Join waitlist</button>
                </div>
              </form>
            )}
            {error && <p className="text-rose-700 mt-5 ml-3">{error}</p>}
          </div>
          <div className='flex-1 flex justify-center items-center bg-center bg-cover'>
            <Image
              src={bigShoe1}
              alt='shoe collection'
              width={610}
              height={500}
              className='object-contain'
            />
          </div>
          </section>
          <section className="sm:px-16 px-8 sm:py-24 py-12">
            <Services />
          </section>
          <Footer />
        </main>
      )
    }
Enter fullscreen mode Exit fullscreen mode

Without the "use client" in the code above, you may encounter this error, as shown.

client compoents error

To learn more about this error, check this documentation on using client components in Next.js.

The final demo should look like this: showing some validation error if no email is typed or clicking the button on an empty input field.

demo app

Conclusion

Xata integration with Next.js is excellent for building your ideas and capturing user data on the backend without so much effort in setting up the architecture yourself from scratch.

Check out the documentation if you want to learn about Xata and its use case with other frameworks.

Top comments (0)