Build a Map Application on AWS in 10 Steps
Tags: javascript, webdev, aws, programming
Published: 2022-04-12 15:52:32

> **June 27, 2024:** This blog post uses Amplify Gen 1, if you're starting a new Amplify app I recommend trying out [Gen 2](https://dev.to/aws/introducing-a-new-fullstack-typescript-dx-for-aws-1ap9)!

Last week, the team I work on at [AWS Amplify](https://docs.amplify.aws/) launched new [map UI components](https://ui.docs.amplify.aws/components/geo). I wanted to take this opportunity to show what you can build using Amplify Geo and Amplify Studio together!

I'm an avid hiker, and [AllTrails](https://www.alltrails.com/) is one of my favorite sites, I duplicated a very, very small portion of their UI for this tutorial!

{% youtube https://youtu.be/0IAORAf3WcY %}

## 1. Create a new Studio Instance
   
Head to the [Amplify Console](https://console.aws.amazon.com/amplify) and select build a new app.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/peu7bumom25039hrqyka.png)

Once your Studio instance is deployed, click "Launch Studio".

## 2. Create your data model

Once you're in Studio, click "Data" under "Set up" on the lefthand navigation. Add one model, `Hike`. Add the fields `name`, `difficulty`, `location`, `lat`, `long`, `length`, `time`, and `coverImage`. `lat`, `long`, and `length` should be floats, all other fields should be strings.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/05s8i67a1ffgeef0x412.png)

Once you've implemented your data model, click "Save and Deploy"!

Now, go to the "Content" tab under "Manage" and add a few hikes! You can find the latitude and longitude by Googling "trail name lat and long".

## 3. Enable auth

Once your data model is done deploying, go to "Authentication" under "Set up". Then deploy the default authentication mode. We won't implement a full sign in flow, though you can learn about how to [here](https://dev.to/aspittel/a-complete-guide-to-the-amplify-react-authentication-components-11p1), we will just need auth enabled to enable mapping.

## 4. Change UI components in Figma

Head to the [AWS Amplify UI Kit](https://www.figma.com/community/file/1047600760128127424). Duplicate the Figma file to your account, and then head to the "My Components" page. You'll see a "CardB" card which we will modify for our app. 

1. Round the card corners by adding a border-radius to the card and the top corners of the image.
2. Copy a small button from the `Primitives` page and paste it onto the card.
3. Change what's currently an address into three separate text fields, the middle one being a dot character.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/alovc58ksyle6dct158z.png)

When you're done, your card should look similar to the above.

I also deleted the components I'm not using.

## 5. Figma to Code
  
Then, back in Studio, head to the "UI Library" page. Click "Get Started" and paste in the link to your Figma file. Then accept all of your components.

Then, click on the `CardB` component on the "UI Library" page. Then click "Configure". Once here, we'll bind data to our component!

Click the image, then set the `src` to the `hike.coverImage`. Then, click the `$99 USD` and set the `label` to `hike.name`. Set the information about the beds/baths/sqft to the name of the `hike.location`. 

Set the button label to `hike.difficulty`. I also want this element to be a div instead of a button - so I'll set the `as` prop to "div".

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6gwj1z0eotmmut0gkftg.png)

I'll set the first text field under that to a concatenated property: `hike.length` + ` miles `. I set the second one to the `hike.time`.

My final card looks like this:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2zgduykgjh0c03g0372k.png)

I want to display all my hikes in a list, so I'll create a collection. Click the "Create a collection" button on the right side. I called my collection `Hikes`.

Add margin as needed on the right side, and I added search and pagination. I kept the dataset as is, though you can add sorts or filters as desired.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6khzfmy2htzocdejukrh.png)

## 6. Setup Local Code

Now we're ready to integrate this list into our app! First, create a React app:

`npx create-react-app amplify-maps`

Install the Amplify libraries and React components:

`npm i aws-amplify @aws-amplify/ui-react`

Run Amplify pull for your project. In Studio on the top right corner, you'll see a "Local setup instructions" link with a unique command for your app. Run this in your command line.

`amplify pull --appId your-app-id --envName staging`

Then, configure Amplify within your `index.js` file:

```js
// Add needed imports
import { Amplify } from 'aws-amplify'
import config from './aws-exports'
import { AmplifyProvider } from '@aws-amplify/ui-react'

import '@aws-amplify/ui-react/styles.css'

// Configure Amplify
Amplify.configure(config)

// use the Amplify Provider component to intialize CSS
ReactDOM.render(
  <AmplifyProvider>
    <App />
  </AmplifyProvider>,
  document.getElementById('root')
)
```

Now, go to your `App.js` file and import the `Hikes` component.


```js
import { Hikes } from './ui-components'
```

Replace the body of your `App.js` file with the following:

```js
function App () {
  return (
    <div className='container'>
      <Hikes />
    </div>
  )
}
```
Now, if you run your React server, you'll see your list of hikes on the page!

## 7. Add Geo

Let's add the map to our application. First, we'll need to initialize [Amplify Geo](https://docs.amplify.aws/lib/geo/getting-started/q/platform/js/).

Run `amplify add geo` from your command line.

Answer the ensuing questions with the following:

```js
? Select which capability you want to add: Map (visualize the geospatial data)
✔ Provide a name for the Map: (enter for default)
✔ Who can access this Map? · Authorized and Guest users
Available advanced settings:
- Map style & Map data provider (default: Streets provided by Esri)

✔ Do you want to configure advanced settings? (y/N) · no
```
Now, run `amplify push` in order to deploy your changes.

## 8. Add a map to your UI

Now, we'll use the [Amplify Geo UI components](https://ui.docs.amplify.aws/components/geo) to add a map to the page. I'll use Denver's latitude and longitude as the center of my map. You also may want to play around with the initial Zoom level.

```js
import { MapView } from '@aws-amplify/ui-react'

...

function App () {
  return (
    <div className='container'>
      <Hikes />
      <MapView
        initialViewState={{
          latitude: 39.113014,
          longitude: -105.358887,
          zoom: 7
        }}
      />
    </div>
  )
}
```

Now, let's add markers to the map for each hike! I'll add a `useEffect` to query for all of my Hikes.

```js
// Add needed imports
import { useEffect, useState } from 'react'
import { Hike } from './models'
import { DataStore } from 'aws-amplify'


...

// at the top of App.js pull all the hikes and store them in state
const [hikes, setHikes] = useState([])
useEffect(() => {
 const getHikes = async () => {
   const hikes = await DataStore.query(Hike)
   setHikes(hikes)
 }
 getHikes()
}, [])
```
Now, let's loop through the hikes and add a `Marker` instance for each with its latitude and longitude:

```js
import { Marker } from 'react-map-gl'

...

function App () {
  return (
    <div className='container'>
      <Hikes />
      <MapView
        initialViewState={{
          latitude: 39.113014,
          longitude: -105.358887,
          zoom: 7
        }}
      >
        {hikes.map(hike => (
          <Marker
            latitude={hike.lat}
            longitude={hike.long}
            key={hike.id}
        />))}
      </MapView>
    </div>
  )
}
```

Now your map should look something like this:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jrzwwtbn0jeb8xihx9o7.png)

## 9. Add popups

Now we have a map with markers on it, let's add popups when a marker is clicked on so you can see more info about the hike! I'll render the `CardB` component if the popup is open.

```js
// Import the Popup
import { Marker, Popup } from 'react-map-gl'

...

function MarkerWithPopup ({ hike, latitude, longitude }) {
  const [showPopup, setShowPopup] = useState(false)

  // event listener that toggles whether the popup is displayed
  const handleMarkerClick = ({ originalEvent }) => {
    originalEvent.stopPropagation()
    setShowPopup(true)
  }

  // render the marker and the popup, render the CardB again within the popup.
  return (
    <>
      <Marker
        latitude={latitude}
        longitude={longitude}
        onClick={handleMarkerClick}
      />
      {showPopup && (
        <Popup
          latitude={latitude}
          longitude={longitude}
          offset={{ bottom: [0, -40] }}
          onClose={() => setShowPopup(false)}
          maxWidth='95%'
          closeOnMove
        >
          <CardB hike={hike} />
        </Popup>
      )}
    </>
  )
}
```

Change the application to display the `MarkerWithPopup` instead of just the original marker!

```js
{
  hikes.map(hike => (
    <MarkerWithPopup
      latitude={hike.lat}
      longitude={hike.long}
      hike={hike}
      key={hike.id}
    />)
  )
}
```

## 10. Add Styling

I also added the following CSS to my `index.css` file, please forgive the `!important`s! They were needed to override the existing styling on the popups!

```css
@import url('https://fonts.googleapis.com/css2?family=Inter:slnt,wght@-10..0,100..900&display=swap');

.container {
  display: flex;
}

.maplibregl-popup-content, .mapboxgl-popup-content {
  background-color: transparent !important;
  box-shadow: none !important;
  border-radius: none !important;
  z-index: 5 !important;
  max-width: 95% !important;
}

.maplibregl-popup-close-button, .mapboxgl-popup-close-button {
  color: white !important;
  font-size: 30px !important;
  font-weight: bold;
}
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q42yp3xfgof1i2wjlz3y.png)

Now your app should have working popups when you click on a marker!

## Conclusion

In this tutorial, we used Amplify Studio, the Amplify CLI, and Amplify UI components to build out a map interface. If you want to delete the resources used in this tutorial, run `amplify delete` in your CLI. I would love to hear your feedback as you build with Amplify, especially since Studio is still in developer preview at the time of this writing!