github icon

github icon

Create View a Listing Page

July 20, 2020


In this chapter we will create the page that will allow users to view an individual listing.

In the pages directory create a ViewListing.js file and add the following:

import React from "react"
import RedBlockButton from "../components/buttons/RedBlockButton"
import { useQuery } from "@apollo/react-hooks"
import { GET_A_LISTING } from "../graphql/Queries"
import activy from "../assets/trip_type.svg"
import amenities from "../assets/trip_activity.svg"
import LandingHeader from "../components/navs/LandingHeader"
import { Skeleton } from "antd"

import {
  HeadingOne,
  HeadingTwo,
  HeadingThree,
  BodyOne,
} from "../components/typography"
const ViewListing = props => {
  const { loading, data, error } = useQuery(GET_A_LISTING, {
    variables: {
      listingId: props.id,
    },
  })

  if (loading) return <Skeleton />
  if (error) return <p className="text-red">{error}</p>

  const listing = data.getAListing
  return (
    <>
      <LandingHeader imgURL={listing.coverPhoto} />
      <div className="grid grid-cols-13 p-5 mt-10">
        <div className="mr-16">
          <HeadingOne className="font-display  font-semibold text-3xl text-black">
            {listing.listingName}
          </HeadingOne>
          <HeadingTwo className="font-display text-xl text-black mt-4 mb-8">
            {listing.listingLocation}
          </HeadingTwo>
          <HeadingThree className="font-display font-bold text-xl text-center s:text-left mb-5 text-black ">
            $ {listing.price}
          </HeadingThree>
          <BodyOne className="font-display text-left text-black ">
            {listing.listingDescription}
          </BodyOne>

          <HeadingThree className="font-display text-2xl font-bold text-black mt-10">
            Trip ammenities
          </HeadingThree>

          <div className="flex flex-col p-3" key="types">
            {listing.listingType.map((t, index) => (
              <div key={index} className="flex flex-row">
                <img src={activy} alt="activity" />
                <BodyOne className="font-display ml-2 mt-2">{t.name}</BodyOne>
              </div>
            ))}
          </div>

          <HeadingThree className="font-display text-2xl font-bold text-black  mt-10">
            Activites
          </HeadingThree>
          <div className="flex flex-col p-3" key="activies">
            {listing.listingActivities.map((a, index) => (
              <div key={index} className="flex flex-row">
                <img src={amenities} alt="amend" />
                <BodyOne className="font-display ml-2 mt-2">{a.name}</BodyOne>
              </div>
            ))}
          </div>
        </div>
        <div className="flex flex-col ">
          <div>
            <RedBlockButton
              onClick={() => props.navigate(`/booking/${props.id}`)}
              className=" text-center s:pr-20 mb-10 mt-10"
            >
              Book
            </RedBlockButton>
          </div>
          <div>
            <HeadingThree className="font-display text-xl   text-black mt-10 mb-10">
              Your guide
            </HeadingThree>
            <img
              src={listing.guide.Avatar}
              alt="guide"
              className="rounded-lg h-48"
            />
          </div>
          <div>
            <HeadingThree className="font-display text-xl   text-black mt-10">
              {listing.guide.Name}
            </HeadingThree>
            <BodyOne className="font-display   text-black mt-5 ">
              {listing.guide.Bio}
            </BodyOne>
          </div>
        </div>
      </div>
    </>
  )
}

export default ViewListing

πŸ‘οΈ Like with the getAllListings query we are hit the GET_A_LISTING query however we are passing in the listingId as the variable which we are getting from the URL of this component.

πŸ‘οΈ In our Return block we have basic markup with CSS Grid to display the content of the listing in a responsive manner. We also map over the activities and types with icons.

Next up go into the Queries.js file and add the following schema doc:

export const GET_A_LISTING = gql`
  query GetAListing($listingId: String!) {
    getAListing(listingId: $listingId) {
      coverPhoto
      listingId
      listingName
      listingType {
        name
      }
      listingLocation
      listingActivities {
        name
      }
      listingDescription
      price
      numberOfDays
      guide {
        Bio
        Name
        Avatar
      }
      specialType
    }
  }
`

πŸ‘οΈ For this specific query we are specifing that the listingId is a string and we are querying all the fields from the listing Type

Next go over to the routes.js file and add the following:

import React from "react"
import { Router } from "@reach/router"
import Home from "./pages/index"
import ViewListing from "./pages/ViewListing"
const Routes = ({ props }) => {
  return (
    <Router>
      <Home path="/" props={props} />
      <ViewListing path="/listing/:id" props={props} />
    </Router>
  )
}

export default Routes

πŸ‘οΈ All we doing here is making our ViewListing component accessabile on the /listing/:id route, where we will swap :id for the actual id of the listing from the server to enable us to query the API for the listing data.

πŸ‘οΈ By passing down the props into the components we can pass down functions from Reach router and other utils so that it is accessible in other parts of the application.

Now you should be able to view any listing.

view-a-listing

Chapters

Backend

Frontend