Create an Events App using Next.js
Published: 2023-01-19 19:28:30

Creating an event app using Next.js can be a great way to build a fast, performant, and scalable web application. In this tutorial, we will go through the process of building an event app from scratch using Next.js, a popular framework for building server-rendered React applications.

First, let's start by setting up our development environment. We will need Node.js and npm (or yarn) installed on our machine. Once we have that, we can create a new Next.js project by running the following command:

`npx create-next-app my-events-app
`

This will create a new directory called "my-events-app" with the basic structure of a Next.js app. We can then navigate into the new directory and start the development server by running:

```
cd my-events-app
npm run dev
```

Now that our development environment is set up, we can start building our event app. We will be using a few external libraries to help us with some of the functionality, such as date handling and form validation. We can install these libraries by running the following commands:

```
npm install moment
npm install yup
```

Next, let's create a new directory called "components" in the "src" directory. Inside this new directory, we will create a new file called "EventForm.js", which will contain the form for creating a new event. This form will include fields for the event name, location, date, and time. We will also include validation for these fields using the "yup" library.

```
import React from 'react'
import { Formik, Form, Field } from 'formik'
import * as Yup from 'yup'

const EventForm = () => {
  const validationSchema = Yup.object().shape({
    name: Yup.string().required('Event name is required'),
    location: Yup.string().required('Event location is required'),
    date: Yup.date().required('Event date is required'),
    time: Yup.string().required('Event time is required'),
  })

  return (
    <Formik
      initialValues={{
        name: '',
        location: '',
        date: '',
        time: '',
      }}
      validationSchema={validationSchema}
      onSubmit={(values, { setSubmitting }) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2))
          setSubmitting(false)
        }, 400)
      }}
    >
      {({ isSubmitting }) => (
        <Form>
          <Field type="text" name="name" placeholder="Event name" />
          <Field type="text" name="location" placeholder="Event location" />
          <Field type="date" name="date" placeholder="Event date" />
          <Field type="time" name="time" placeholder="Event time" />
          <button type="submit" disabled={isSubmitting}>
            Create event
          </button>
        </Form>
      )}
    </Formik>
  )
}

export default EventForm

```
Now that we have our form set up, we can use it in our "pages/index.js" file to render it on the homepage of our app.

We will also use the "moment" library to format the date and time fields in a more user-friendly format.

```
import React from 'react'
import EventForm from '../components/EventForm'
import moment from 'moment'

const Home = () => {
  const handleSubmit = values => {
    const { name, location, date, time } = values
    const formattedDate = moment(date).format('MM/DD/YYYY')
    const formattedTime = moment(time, 'HH:mm').format('h:mm a')

    alert(`Event name: ${name}\nEvent location: ${location}\nEvent date: ${formattedDate}\nEvent time: ${formattedTime}`)
  }

  return (
    <div>
      <EventForm onSubmit={handleSubmit} />
    </div>
  )
}

export default Home

```

Now, we have a functional form for creating new events. However, we will also want to display a list of all the events that have been created. To do this, we will create a new component called "EventList" in our "components" directory. This component will take in an array of events and map over them to display each event's name, location, and date/time.

```
import React from 'react'
import moment from 'moment'

const EventList = ({ events }) => {
  return (
    <div>
      {events.map(event => (
        <div key={event.id}>
          <h2>{event.name}</h2>
          <p>Location: {event.location}</p>
          <p>
            Date: {moment(event.date).format('MM/DD/YYYY')} Time:{' '}
            {moment(event.time, 'HH:mm').format('h:mm a')}
          </p>
        </div>
      ))}
    </div>
  )
}

export default EventList

```
We can then use this component in our "pages/index.js" file to display the list of events, and also pass in the new event that was just created to the list of events.

```
import React, { useState } from 'react'
import EventForm from '../components/EventForm'
import EventList from '../components/EventList'

const Home = () => {
  const [events, setEvents] = useState([])

  const handleSubmit = values => {
    const { name, location, date, time } = values
    const formattedDate = moment(date).format('MM/DD/YYYY')
    const formattedTime = moment(time, 'HH:mm').format('h:mm a')

    const newEvent = {
      id: Date.now(),
      name,
      location,
      date: formattedDate,
      time: formattedTime
    }

    setEvents([...events, newEvent])
  }

  return (
    <div>
      <EventForm onSubmit={handleSubmit} />
      <EventList events={events} />
    </div>
  )
}

export default Home

```
With this, we now have a fully functional events app that allows users to create new events and view a list of all events

## Styling our Events App

Now that we have set up emotion, we can use the styled function to create CSS styles for our components. We can create a new directory called "styles" within our "components" directory, and add a new file called "EventForm.js" where we will define the styles for our EventForm component.

```
import styled from '@emotion/styled'

const FormContainer = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 2rem;
`

const FormField = styled.div`
  display: flex;
  flex-direction: column;
  margin-bottom: 1rem;
`

const FormLabel = styled.label`
  font-size: 1.6rem;
  margin-bottom: 0.5rem;
`

const FormInput = styled.input`
  padding: 0.5rem;
  font-size: 1.6rem;
  border-radius: 0.5rem;
  border: none;
`

const FormButton = styled.button`
  background-color: #0070f3;
  color: #fff;
  padding: 1rem 2rem;
  font-size: 1.6rem;
  border-radius: 0.5rem;
  border: none;
  cursor: pointer;
  &:disabled {
    background-color: #aaa;
  }
`

export { FormContainer, FormField, FormLabel, FormInput, FormButton }

```

We can then import these styles in our EventForm component and apply them to the relevant elements.

```
import React from 'react'
import { Formik, Form, Field } from 'formik'
import * as Yup from 'yup'
import { FormContainer, FormField, FormLabel, FormInput, FormButton } from '../styles/EventForm'

const EventForm = () => {
  const validationSchema = Yup.object().shape({
    name: Yup.string().required('Event name is required'),
    location: Yup.string().required('Event location is required'),
    date: Yup.date().required('Event date is required'),
    time: Yup.string().required('Event time is required'),
  })

  return (
    <FormContainer>
      <Formik
        initialValues={{
          name: '',
          location: '',
          date: '',
          time: '',
        }}
        validationSchema={validationSchema}
        onSubmit={(values, { setSubmitting }) => {
          setTimeout(() => {
            alert(JSON.stringify(values, null, 2))
            setSubmitting(false)
          }, 400)
        }}
      >
        {({ isSubmitting }) => (
          <Form>
            <FormField>
              <FormLabel htmlFor="name">Event name</FormLabel>
              <FormInput type="text" name="name" placeholder="Event name" />
            </FormField>
            <FormField>
              <FormLabel htmlFor="location">Event location</FormLabel>
              <FormInput type="text" name="location" placeholder="Event location" />
            </FormField>
            <FormField>
              <FormLabel htmlFor="date">Event date</FormLabel>
              <FormInput type="date" name="date" placeholder="Event date" />
            </FormField>
            <FormField>
              <FormLabel htmlFor="time">Event time</FormLabel>
              <FormInput type="time" name="time" placeholder="Event time" />
            </FormField>
            <FormButton type="submit" disabled={isSubmitting}>
              Create event
            </FormButton>
          </Form>
        )}
      </Formik>
    </FormContainer>
  )
}

export default EventForm

```
In this way, we have a functional events app with a form for creating new events and displaying a list of all events, with styling using Emotion.
It's also worth noting that this is just a simple example, in real-world scenarios you would use a state management library like redux or context-api to store the events and manage the state instead of using react useState hook. Additionally, you would also use an API to persist the data, either by using a backend or a cloud service like Firebase.