Airbnb clone, use the database instead of the file

This post is part of a new series where we build a clone of Airbnb with Next.js. See the first post here.

Now that we created the model that uses the DB to serve the data, it’s time to use it!

First, I’m going to manually add the houses data we had in the file to the database, creating 2 rows in the houses table:

Now, the houses.js file is imported by 2 files:

  • pages/houses/[id].js
  • pages/index.js

We need to change this reliance on the file, and use a new API instead.

Let’s work on the list page first.

Houses list

Instead of loading the houses from the JSON file, we’re going to use the House model.

We can use the model inside the getServerSideProps() method. Next.js becomes an hybrid between frontend and backend.

Let’s start from pages/index.js.

We can import the model:

import { House as HouseModel } from '../model.js'

Then in getServerSideProps() we get the houses using:

const houses = await HouseModel.findAndCountAll()

and we return the value iterating over the results, getting the dataValues property, which returns a plain JS object with the data we need:

return {
  props: {
    nextbnb_session: nextbnb_session || null,
    houses: houses.rows.map((house) => house.dataValues)
  }
}

Now we get houses as a prop in the Home component:

export default function Home({ nextbnb_session, houses }) {
  //...

and we need to do a little refactoring of how we print the JSX. We need to embed the content inside the JSX, otherwise it can’t access the value of the prop, like this:

import House from '../components/House'
import Layout from '../components/Layout'
import Cookies from 'cookies'
import { useStoreActions } from 'easy-peasy'
import { useEffect } from 'react'
import { House as HouseModel } from '../model.js'

export default function Home({ nextbnb_session, houses }) {
  const setLoggedIn = useStoreActions((actions) => actions.login.setLoggedIn)

  useEffect(() => {
    if (nextbnb_session) {
      setLoggedIn(true)
    }
  }, [])

  return (
    <Layout
      content={
        <div>
          <h2>Places to stay</h2>

          <div className="houses">
            {houses.map((house, index) => {
              return <House key={index} {...house} />
            })}
          </div>

          <style jsx>{`
            .houses {
              display: grid;
              grid-template-columns: 49% 49%;
              grid-template-rows: 300px 300px;
              grid-gap: 2%;
            }
          `}</style>
        </div>
      }
    />
  )
}

export async function getServerSideProps({ req, res, query }) {
  const cookies = new Cookies(req, res)
  const nextbnb_session = cookies.get('nextbnb_session')
  const houses = await HouseModel.findAndCountAll()

  return {
    props: {
      nextbnb_session: nextbnb_session || null,
      houses: houses.rows.map((house) => house.dataValues)
    }
  }
}

The house detail

We do the same in pages/houses/[id].js.

We import the model:

import { House as HouseModel } from '../../model.js'

Then we use it to get the house by id:

const house = await HouseModel.findByPk(id)

and we can return its dataValues in the return object:

return {
  props: {
    house: house.dataValues,
    nextbnb_session: nextbnb_session || null
  }
}

In this case we were already returning a house prop, so nothing needs to be changed.

Here is the full source code:

import Head from 'next/head'
import Layout from '../../components/Layout'
import DateRangePicker from '../../components/DateRangePicker'
import { useState, useEffect } from 'react'
import { useStoreActions } from 'easy-peasy'
import Cookies from 'cookies'
import { House as HouseModel } from '../../model.js'

const calcNumberOfNightsBetweenDates = (startDate, endDate) => {
  const start = new Date(startDate) //clone
  const end = new Date(endDate) //clone
  let dayCount = 0

  while (end > start) {
    dayCount++
    start.setDate(start.getDate() + 1)
  }

  return dayCount
}

export default function House({ house, nextbnb_session }) {
  const [dateChosen, setDateChosen] = useState(false)
  const [numberOfNightsBetweenDates, setNumberOfNightsBetweenDates] =
    useState(0)

  const setShowLoginModal = useStoreActions(
    (actions) => actions.modals.setShowLoginModal
  )

  const setLoggedIn = useStoreActions((actions) => actions.login.setLoggedIn)

  useEffect(() => {
    if (nextbnb_session) {
      setLoggedIn(true)
    }
  }, [])

  return (
    <Layout
      content={
        <div className="container">
          <Head>
            <title>{house.title}</title>
          </Head>
          <article>
            <img src={house.picture} width="100%" alt="House picture" />
            <p>
              {house.type} - {house.town}
            </p>
            <p>{house.title}</p>
          </article>
          <aside>
            <h2>Choose a date</h2>
            <DateRangePicker
              datesChanged={(startDate, endDate) => {
                setNumberOfNightsBetweenDates(
                  calcNumberOfNightsBetweenDates(startDate, endDate)
                )
                setDateChosen(true)
              }}
            />

            {dateChosen && (
              <div>
                <h2>Price per night</h2>
                <p>${house.price}</p>
                <h2>Total price for booking</h2>
                <p>${(numberOfNightsBetweenDates * house.price).toFixed(2)}</p>
                <button
                  className="reserve"
                  onClick={() => {
                    setShowLoginModal()
                  }}
                >
                  Reserve
                </button>{' '}
              </div>
            )}
          </aside>

          <style jsx>{`
            .container {
              display: grid;
              grid-template-columns: 60% 40%;
              grid-gap: 30px;
            }

            aside {
              border: 1px solid #ccc;
              padding: 20px;
            }
          `}</style>
        </div>
      }
    />
  )
}

export async function getServerSideProps({ req, res, query }) {
  const { id } = query
  const cookies = new Cookies(req, res)
  const nextbnb_session = cookies.get('nextbnb_session')
  const house = await HouseModel.findByPk(id)

  return {
    props: {
      house: house.dataValues,
      nextbnb_session: nextbnb_session || null
    }
  }
}

You can now remove the houses.js file, but before doing so, add the data to the database:

TIP: In the owner field, add the id of a user, like 1 for example. This associates the house to a user in our database.

See the code on GitHub


This content originally appeared on flaviocopes.com and was authored by flaviocopes.com

This post is part of a new series where we build a clone of Airbnb with Next.js. See the first post here.

Now that we created the model that uses the DB to serve the data, it’s time to use it!

First, I’m going to manually add the houses data we had in the file to the database, creating 2 rows in the houses table:

Now, the houses.js file is imported by 2 files:

  • pages/houses/[id].js
  • pages/index.js

We need to change this reliance on the file, and use a new API instead.

Let’s work on the list page first.

Houses list

Instead of loading the houses from the JSON file, we’re going to use the House model.

We can use the model inside the getServerSideProps() method. Next.js becomes an hybrid between frontend and backend.

Let’s start from pages/index.js.

We can import the model:

import { House as HouseModel } from '../model.js'

Then in getServerSideProps() we get the houses using:

const houses = await HouseModel.findAndCountAll()

and we return the value iterating over the results, getting the dataValues property, which returns a plain JS object with the data we need:

return {
  props: {
    nextbnb_session: nextbnb_session || null,
    houses: houses.rows.map((house) => house.dataValues)
  }
}

Now we get houses as a prop in the Home component:

export default function Home({ nextbnb_session, houses }) {
  //...

and we need to do a little refactoring of how we print the JSX. We need to embed the content inside the JSX, otherwise it can’t access the value of the prop, like this:

import House from '../components/House'
import Layout from '../components/Layout'
import Cookies from 'cookies'
import { useStoreActions } from 'easy-peasy'
import { useEffect } from 'react'
import { House as HouseModel } from '../model.js'

export default function Home({ nextbnb_session, houses }) {
  const setLoggedIn = useStoreActions((actions) => actions.login.setLoggedIn)

  useEffect(() => {
    if (nextbnb_session) {
      setLoggedIn(true)
    }
  }, [])

  return (
    <Layout
      content={
        <div>
          <h2>Places to stay</h2>

          <div className="houses">
            {houses.map((house, index) => {
              return <House key={index} {...house} />
            })}
          </div>

          <style jsx>{`
            .houses {
              display: grid;
              grid-template-columns: 49% 49%;
              grid-template-rows: 300px 300px;
              grid-gap: 2%;
            }
          `}</style>
        </div>
      }
    />
  )
}

export async function getServerSideProps({ req, res, query }) {
  const cookies = new Cookies(req, res)
  const nextbnb_session = cookies.get('nextbnb_session')
  const houses = await HouseModel.findAndCountAll()

  return {
    props: {
      nextbnb_session: nextbnb_session || null,
      houses: houses.rows.map((house) => house.dataValues)
    }
  }
}

The house detail

We do the same in pages/houses/[id].js.

We import the model:

import { House as HouseModel } from '../../model.js'

Then we use it to get the house by id:

const house = await HouseModel.findByPk(id)

and we can return its dataValues in the return object:

return {
  props: {
    house: house.dataValues,
    nextbnb_session: nextbnb_session || null
  }
}

In this case we were already returning a house prop, so nothing needs to be changed.

Here is the full source code:

import Head from 'next/head'
import Layout from '../../components/Layout'
import DateRangePicker from '../../components/DateRangePicker'
import { useState, useEffect } from 'react'
import { useStoreActions } from 'easy-peasy'
import Cookies from 'cookies'
import { House as HouseModel } from '../../model.js'

const calcNumberOfNightsBetweenDates = (startDate, endDate) => {
  const start = new Date(startDate) //clone
  const end = new Date(endDate) //clone
  let dayCount = 0

  while (end > start) {
    dayCount++
    start.setDate(start.getDate() + 1)
  }

  return dayCount
}

export default function House({ house, nextbnb_session }) {
  const [dateChosen, setDateChosen] = useState(false)
  const [numberOfNightsBetweenDates, setNumberOfNightsBetweenDates] =
    useState(0)

  const setShowLoginModal = useStoreActions(
    (actions) => actions.modals.setShowLoginModal
  )

  const setLoggedIn = useStoreActions((actions) => actions.login.setLoggedIn)

  useEffect(() => {
    if (nextbnb_session) {
      setLoggedIn(true)
    }
  }, [])

  return (
    <Layout
      content={
        <div className="container">
          <Head>
            <title>{house.title}</title>
          </Head>
          <article>
            <img src={house.picture} width="100%" alt="House picture" />
            <p>
              {house.type} - {house.town}
            </p>
            <p>{house.title}</p>
          </article>
          <aside>
            <h2>Choose a date</h2>
            <DateRangePicker
              datesChanged={(startDate, endDate) => {
                setNumberOfNightsBetweenDates(
                  calcNumberOfNightsBetweenDates(startDate, endDate)
                )
                setDateChosen(true)
              }}
            />

            {dateChosen && (
              <div>
                <h2>Price per night</h2>
                <p>${house.price}</p>
                <h2>Total price for booking</h2>
                <p>${(numberOfNightsBetweenDates * house.price).toFixed(2)}</p>
                <button
                  className="reserve"
                  onClick={() => {
                    setShowLoginModal()
                  }}
                >
                  Reserve
                </button>{' '}
              </div>
            )}
          </aside>

          <style jsx>{`
            .container {
              display: grid;
              grid-template-columns: 60% 40%;
              grid-gap: 30px;
            }

            aside {
              border: 1px solid #ccc;
              padding: 20px;
            }
          `}</style>
        </div>
      }
    />
  )
}

export async function getServerSideProps({ req, res, query }) {
  const { id } = query
  const cookies = new Cookies(req, res)
  const nextbnb_session = cookies.get('nextbnb_session')
  const house = await HouseModel.findByPk(id)

  return {
    props: {
      house: house.dataValues,
      nextbnb_session: nextbnb_session || null
    }
  }
}

You can now remove the houses.js file, but before doing so, add the data to the database:

TIP: In the owner field, add the id of a user, like 1 for example. This associates the house to a user in our database.

See the code on GitHub


This content originally appeared on flaviocopes.com and was authored by flaviocopes.com


Print Share Comment Cite Upload Translate Updates
APA

flaviocopes.com | Sciencx (2021-12-23T05:00:00+00:00) Airbnb clone, use the database instead of the file. Retrieved from https://www.scien.cx/2021/12/23/airbnb-clone-use-the-database-instead-of-the-file/

MLA
" » Airbnb clone, use the database instead of the file." flaviocopes.com | Sciencx - Thursday December 23, 2021, https://www.scien.cx/2021/12/23/airbnb-clone-use-the-database-instead-of-the-file/
HARVARD
flaviocopes.com | Sciencx Thursday December 23, 2021 » Airbnb clone, use the database instead of the file., viewed ,<https://www.scien.cx/2021/12/23/airbnb-clone-use-the-database-instead-of-the-file/>
VANCOUVER
flaviocopes.com | Sciencx - » Airbnb clone, use the database instead of the file. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/12/23/airbnb-clone-use-the-database-instead-of-the-file/
CHICAGO
" » Airbnb clone, use the database instead of the file." flaviocopes.com | Sciencx - Accessed . https://www.scien.cx/2021/12/23/airbnb-clone-use-the-database-instead-of-the-file/
IEEE
" » Airbnb clone, use the database instead of the file." flaviocopes.com | Sciencx [Online]. Available: https://www.scien.cx/2021/12/23/airbnb-clone-use-the-database-instead-of-the-file/. [Accessed: ]
rf:citation
» Airbnb clone, use the database instead of the file | flaviocopes.com | Sciencx | https://www.scien.cx/2021/12/23/airbnb-clone-use-the-database-instead-of-the-file/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.