DEV Community

Amanda Toop
Amanda Toop

Posted on • Updated on

Coding up a React Travel Journal

I now have two slightly more complicated React projects under my belt. The first, an AirBnB Experiences Clone app, I did as a code-along project with Scrimba. (Link to repo.)

Image description

airbnb Experiences Clone

This airbnb experiences clone app pulled in a data file of "experiences" objects, converted them to an array of objects, and then mapped each object to Card() component, which output each objects relevant data in formatted html. The entire project was then styled with CSS.

Here is the code from my container app - App.js:

import logo from './logo.svg';
import Top from "./components/Top"
import Card from "./components/Card"
import photoexperience from "./images/katie-zaferes.png"
import CardData from "./data"

// note had to find custom image solution - https://delftstack.com/howto/react/react-img-src/

function App() {

  //note assign key to eliminate key error
  // pass entire object to Card()
  const cardElements = CardData.map((card)=>{
    return <Card 
    key={card.id}
    card={card}/>
  })

  // console.log("cardElements: ", cardElements)


  return (
   <div>
    <Top />
    <div className="experience-photos">{cardElements}</div>
   </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Here is the code from the Card.js component:

import React from "react"
import photoexperience from "../images/katie-zaferes.png"
import star from "../images/star.png"

export default function Card(props){

    let badgeText
    if(props.card.openSpots===0){
        badgeText = "Sold-Out"
    } else if (props.card.country === "Online"){
        badgeText = "Online"
    }
    console.log(props.card)
    return <div className="experience-listing">
        {/* conditional display if there is badge text*/}
        {badgeText && <div className="experience-status">{badgeText}</div>}
        <img className="experience-img" src={props.card.coverImg} alt={props.card.title}></img>
        <div className="review-div">
        <img className="star-img" src={star} alt="star"></img>
            <span className="rating">{props.card.stats.rating}</span>
            <span className="review-count grey"> ({props.card.stats.reviewCount}) * </span>
            <span className="country grey"> {props.card.location}</span>

        </div>
        {/* end review div */}
        <p className="experience-heading">{props.card.title}</p>
        <p className="experience-price"><span className="bold">From ${props.card.price}</span> / person</p>
        </div>
        {/* holds one photo */}

    // holds all photos
}
Enter fullscreen mode Exit fullscreen mode

and here is a snippet of the data file:

export default [
    {
        id: 1,
        title: "Life Lessons with Katie Zaferes",
        description: "I will share with you what I call \"Positively Impactful Moments of Disappointment.\" Throughout my career, many of my highest moments only came after setbacks and losses. But learning from those difficult moments is what gave me the ability to rise above them and reach my goals.",
        price: 136,
        coverImg: "katie-zaferes.png",
        stats: {
            rating: 5.0,
            reviewCount: 6
        },
        location: "Online",
        openSpots: 0,
    },
<...>
]
Enter fullscreen mode Exit fullscreen mode

The main problem that I ran into in this tutorial was understanding where image files needed to be stored in order to be accessible. I was able to search for and find this resource, which explained that if you want to import a local image - the image needs to be stored in a subfolder of the src folder in your App. If you are using a data file with photo file names, like I was, then you need to store those images in the public folder, or in a subfolder ("images" for example.)

Image description

Travel Journal App

Next, I used the basic techniques of the airbnb experiences clone to write up a small travel journal app using React. Each travel journal entry displays a location image, link to Google maps, and short description. The format is essentially the same as above in terms of structure. (Link to repo.)

Here is the container app code:

import TravelData from "./data"
import TripCard from './components/tripcard';
import Header from "./components/header"


function App() {
  // get data out of file and into object

  const tripElements = TravelData.map(
    (trip) =>{
      // return <TripCard title={trip.title}/>
      return <TripCard key={trip.id} trip={trip} />
    }
  )
console.log(tripElements)

  return (
    <div>
    <Header />
    <div className="trip-listing">{tripElements}
    </div>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

The TripCard.js component code:

import React from "react"
import MapIcon from "../images/map-pin-solid.svg"

export default function TripCard(props){
    let image = props.trip.imageURL
    console.log(image)
    return <div className="trip-card"><h1 className="trip-title">{props.trip.title}</h1>
    <img className="trip-image" src={props.trip.imageURL} alt={props.trip.title}></img>

    <div className="location">
    <img src={MapIcon} className="location-icon" alt="map pin icon"></img>
    <h2 className="trip-location">{props.trip.location}</h2><a href={props.trip.googleMapsUrl}className="location-link">View on Google Maps</a></div>

    <span className="trip-date">{props.trip.visitDate}</span>
    <p className="trip-description">{props.trip.description}</p>
    </div>
}

Enter fullscreen mode Exit fullscreen mode

and a snippet of the data file object -

export default [
    {
        id: 1,
        title: "Volcanos National Park",
        location:"USA",
        googleMapsUrl:"https://goo.gl/maps/dPk4XiWD7roXFjhx8",
        visitDate:"June 2010",
        description:"Unique destination to spot live lava flows, lava tubes & glowing craters is popular with tourists.",
        photographerCredits:"https://unsplash.com/photos/xfSdarS1wus",
        imageURL:"https://images.unsplash.com/photo-1509780764860-beca5b971c4b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80"

    },
<...>

]
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
tristan_m profile image
Tristan M・トリスタン

Great example of going beyond the tutorials to get some real learning done and come across your own issues!

One small tip regarding the post formatting, three back-ticks followed by language will make your code chunks prettier to look at.

 const jsxDemo = ["Well", "Dang"].map( (element, index) => { return (
    <h1> {index}. {element} </h1>
 )}
Enter fullscreen mode Exit fullscreen mode

Regarding the code itself, I've sent a pull request - accepting it or not is entirely up to you, just wanted to provide a small impromptu code review for styling and consistency across code base.

Have a good one!

Collapse
 
atoopdev profile image
Amanda Toop

Thank you for the tip - I made the code snippet formatting change and it looks much better.

I saw your mini code review and I appreciate you taking the time. Can I ask what the advantage is of switching to
"const Header = () => " instead of using "export default function"?