How I Built The Uber Web-app Clone
Published: 2022-08-03 19:02:03





Hi, this is my first article here, Welcome to my Tech talk.

While trying to order a ride from my uber mobile app some time ago, I navigated through the pages and wondered how the passengers interface flow was developed and put in place. I saw this as a challenge and decided to give it a try by making a web-version clone of it. Luckily for me, while making my research, I stumbled upon the web-app version (which I never knew was in existence) and then decided to make a replica.

In this article, Ill be working you through how I made a clone of the Uber web app passenger's interface using ReactJS and Typescript.

> **_Please note:_** _This is not a tutorial or a code explanation therefore, there will be no detailed code snippet in this article._

Ill start by listing out the technologies (Languages, frameworks, and API) used during the build process.

- **ReactJS with Redux toolkit.**

- **Typescript.**

- **Tailwind.**

- **Tailwind CSS and styles component.**

- **IP Geo-location API.**

- **Google map API.**

- **Firebase API for authentication.**

### React with Redux toolkit.

Due to my experience with [ReactJS](https://reactjs.org/) and some of the flexibility it has, I decided to stick with it in putting up this project. On the other hand, the [Redux-toolkit](https://redux-toolkit.js.org/) has been my favorite tool to use while managing global states as it is highly maintainable, provides ease for testing, and is valuable in [server-side rendering](https://www.gatsbyjs.com/docs/glossary/server-side-rendering/#:~:text=Server%2Dside%20rendering%20means%20using,languages%20such%20as%20PHP%20or%20.).

All global states like the users initial position value and coordinates, the pickup value and coordinates, and the destination value are being managed using the **Redux-toolkit**.

### Typescript.

With this, I was able to specify the data types used across each component and spot bugs early.

### Tailwind CSS and styled component.

Having heard talks about the [Tailwind CSS](https://tailwindcss.com/) and its high customization features, I decided to give it a try. Aside from its high customization features, I was able to build complex responsive layouts and write common utility patterns faster while working on this project. Moreover, [styled components](https://styled-components.com/) allowed me to style my custom components and prevented bugs from my class names.

Even though this project was the first project I implemented them with, I was still able to have easy maintainability on my code-base style.

### IP Geo-location API.

With the [IP Geolocation](https://ipgeolocation.io/documentation/ip-geolocation-api.html), you can get details of a particular user like the **continent name** , **county name** , **city** , **country code** , **currency** , and so on based on the users IP address. My purpose for using this API on this project was to access the users current country code. This country code was used alongside the users input query data while trying to get the place auto-complete result on search. Ill discuss more on that later in this article.

### Google map API.

All Dynamic maps, Direction-routes, Place auto-complete, Distance-matrix, and Drivers current location were implemented by the [Google map API](https://developers.google.com/maps/documentation). Try and follow the article till the end to find out more details about this.

### Firebase API for authentication.

I decided to make things simple by using the [federated identity provider integration](https://www.onelogin.com/learn/federated-identity#:~:text=Federated%20identity%20allows%20authorized%20users,different%20applications%20securely%20and%20efficiently.) for Firebase. Users can sign in with their **Facebook** or **Google accounts** to access the app.

### THE KEY FEATURES AND ITS IMPLEMENTATION.

### The map layout.

If youre familiar with using Google Maps as a developer, youll notice that the default map layout is quite different from that of the **Uber web-app**. I was able to achieve this using the [" Style Reference for Maps "](https://developers.google.com/maps/documentation/javascript/style-reference) to mimic that of [Uber](https://m.uber.com/looking). With the style option from the [Google Maps Docs](https://developers.google.com/maps/documentation/javascript/style-reference), you can easily customize the presentation of the standard Google map styles, changing the visual display of features like **roads** , **parks** , **businesses** , and other points of interest.

I used a `JSON` style declaration to change the color of the Administrative fill geometry, the Landscape filled geometry, and the poi fills geometry. Beyond that, I was able to set the road visibility on, hide the landscape natural terrain, remove all intensity from the color of poi, and so on, as seen in the code base [here](https://github.com/tech-doctor/uber-clone/blob/main/src/Component/map/mapStyle.ts).

Check the code snippet below to have an idea of how this was done.

```
[
  {
    "featureType": "all",
    "stylers": [
      { "color": "#C0C0C0" }
    ]
  },{
    "featureType": "road.arterial",
    "elementType": "geometry",
    "stylers": [
      { "color": "#CCFFFF" }
    ]
  },{
    "featureType": "landscape",
    "elementType": "labels",
    "stylers": [
      { "visibility": "off" }
    ]
  }
]

```

You can declare a variable to the array and set it as the style in your [map option](https://developers.google.com/maps/documentation/javascript/reference/map#MapOptions.styles).

### Places auto-complete.

The [auto-complete](https://developers.google.com/maps/documentation/places/web-service/autocomplete) feature of the **Google Maps Platform** gives a type-ahead search behavior of the Google Maps search field.

The [Place Auto-complete JavaScript library](https://developers.google.com/maps/documentation/javascript/places-autocomplete) has been the usual way to implement the auto-complete feature while working on a web app. However, using this already-made library has some limitations.

I considered using the [Place auto-complete web service](https://developers.google.com/maps/documentation/places/web-service/autocomplete#example_autocomplete_requests) approach which I think will be most suitable to achieve my goal. Because of that, I can customize the style of the result displayed as opposed to using the **Place autocomplete JavaScript library**.

The **Places auto-complete service** returns place prediction in response to an `HTTP` request. The request specifies a textual search string and optional geographic bounds. This service can be used to provide autocomplete functionality for text-based geographic searches by returning places such as businesses, addresses, and points of interest as user types.

The parameters I used to perform this simple action are the [input](https://developers.google.com/maps/documentation/places/web-service/autocomplete#input) which is the text string on which to search, [country](https://developers.google.com/maps/documentation/places/web-service/autocomplete#input) which will restrict the search result to places within the user's country, and of course a **Unique API key**.

The code snippet below gives a clear picture of how this was done.

```
const getPredictions = (input:string) => {
   axios(`https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${input}&components=country:${countryCode !==null?countryCode:'NG' }&key=${GOOGLE_API_KEY}`, {
      method: "GET",
      headers: {
        "Content-Type": "application/json"
      }
    })
    .then( async res => {
      try {
        const response = await res.data;
        const result = response.predictions;
         return result;
      }catch (error) {
        console.log(error);
      }})
  }

```

The `code` above return an array of object as the predicted result.

### Country code.

Having a dynamic country code was not what I initially thought would be needed, but then, I had a second thought.

Following my opinion on how Uber was built, the country code used to get the predicted result will definitely be based on the users location. Having thought of that, I decided to look for a way I could get the users country code just immediately after search-input Is being mounted, after making some research, I came across the [IP Geolocation](https://ipgeolocation.io/documentation/ip-geolocation-api.html) which provides a real-time and accurate Geo-location response.

Following this end-point `https://api.ipgeolocation.io/ipgeo` and using the approach below,

```
const getCountryCode = (IP_KEY) = > {
 fetch(`https://api.ipgeolocation.io/ipgeo?apiKey=${IP_KEY}`)
    .then( async res => {
      try {
        const result = await res.json();
       return result;
      }catch (error) {
        console.log(error);
      }
    })
}

```

a `JSON` object response of **IP** , **host-name** , **city** , **country\_code** and so on is being return as seen below.

```
{
  "ip": "8.8.8.8",
  "hostname": "dns.google",
  "city": "Lagos",
  "country_code2": "NG",

  ...others
}

```

The country\_code2 which is the users country code is now set as the country parameter of the place auto-complete endpoint.

## User current Geo-location.

In late 2016, uber made an update to give the app permission to track location data at all times, which they say will improve **Pickup** and **Drop-off** accuracy. Implementing this feature was a bit straightforward, as Im quite familiar with using the `getCurrentPosition` method. With the [getCurrentPosition](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/getCurrentPosition), I was able to get the current location of the particular users device in terms of their coordinate(latitude and longitude).

```
 if(navigator.geolocation){
   navigator.geolocation.getCurrentPosition(
    (position: GeolocationPosition) => {
     const { latitude, longitude } = position.coords;
      console.log(latitude, longitude);
    }
  )
 }

```

The snippet above logs the current `latitude` and `longitude` of a particular users device location.

It is quite obvious that this form of data will be best for the users experience if displayed in an address format. With the [Reverse Geocoding](https://developers.google.com/maps/documentation/javascript/examples/geocoding-reverse), I was able to achieve this.

### Storing the pickup and destination location data.

Looking closely at the Uber web app, all the **Pickup** and **destination** locations details(address name, coordinates, and place ID) were being stored as a URL parameter. Following this approach was quite helpful in the sense that, I still maintain my location input and info-window state whenever a refresh is being made.

### Direction API.

The [Directional API](https://developers.google.com/maps/documentation/directions/overview) is a service that uses an `HTTP` request to return the most efficient routes. For easy creation of the direction renderer, I used of the [Direction API library for JavaScript](https://developers.google.com/maps/documentation/javascript/directions#Directions).

With that, I was able to create an instance of the direction service and route the direction, passing an object consisting of origin, destination, travel mode, and driving options as an argument. To see how I did this, check the snippet from the project's codebase [HERE](https://github.com/tech-doctor/uber-clone/blob/main/src/Component/map/index.tsx)

### Distance matrix

The travel duration and the drop-off time were calculated using the [distance matrix API] ( https://developers.google.com/maps/documentation/distance-matrix/overview ). This API returns information based on the recommendation route between the starting and the ending point.

```
const getDistance = (origin, end) => {
axios(`https://maps.googleapis.com/maps/api/distancematrix/json?origins=${origin}&destinations=${end}&units=imperial&key=${GOOGLE_API_KEY}`, {
      method: "GET",
      headers: {
        "Content-Type": "application/json"
      }
    })
    .then(async res => {
      try {
        const response = await res;
        const {data} = await response;
        const result = data.rows[0].elements[0];
        return result;
      }
      catch (error:any) {
          console.log(error);
      }
    });
}

```

From the snippet above, the function returns the duration which is an object with the text and value as the key. The text was used to calculate the duration and drop-off time of the journey. The value on the other hand was used to calculate the prices for each journey.

Under normal conditions, the duration and the price of the journey can be gotten directly from the [uber estimate-time](https://developer.uber.com/docs/riders/references/api/v1.2/estimates-time-get) and [uber estimate-price](https://developer.uber.com/docs/riders/references/api/v1.2/estimates-price-get) API endpoints respectively. However, there are a lot of restrictions on that at the time of development.

## Conclusion.

Thanks for following up till the end, a lot has been said already. However, every detail of the development process cannot be stated. You can always refer to the codebase on GitHub [HERE](https://github.com/tech-doctor/uber-clone) for more details.

This is just a brief walkthrough on how I built my version of the [uber-clone](https://m-uber-clone.netlify.app/), I welcome any form of criticism as well as corrections. Thank you.