DEV Community

loading...
Cover image for Firebase + Vue → Track Users Location Real-Time On The Google Maps

Firebase + Vue → Track Users Location Real-Time On The Google Maps

Raja Tamil
Hi I am Raja Tamil • Best Selling Instructor at Udemy • Featured Author @ Medium.com • Founder of SoftAuthor.com (20K visitors/month)
・5 min read

By the end of this tutorial, you’ll be able to:

  • Track individual driver’s location, with their permission, using HTML5 Geolocation API after logging into the app.
  • Store authenticated driver’s location data to the Cloud Firestore as the location changes.
  • Show all of the active driver’s current location in real-time on Google Maps in the Admin view.

🛑 The app will only get location updates as long as it’s in the foreground state and it STOPS giving updates when it’s in the background mode.

What You’ll Make By The End Of This Tutorial

alt text

Infographics

alt text

Table Of Contents

Project Setup

IMAGE ALT TEXT HERE

I have created five page based components in the starter Vue project which are:

  • Login.vue
  • Signup.vue
  • Driver.vue
  • Admin.vue

Before going further, we need to include a couple of files in index.html.

Add a Semantic UI CSS framework to build a UI.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
Enter fullscreen mode Exit fullscreen mode

Also, add the Google Maps JavaScript library CDN link to the project.

<script src="https://maps.googleapis.com/maps/api/js?key=[YOUR_API_KEY]">
Enter fullscreen mode Exit fullscreen mode

IMAGE ALT TEXT HERE

Create A New Firebase User

Of course, we need authentication in place to track multiple drivers at once.

Firebase offers a variety of sign-in methods such as Facebook, Google, etc but I am going to stick with Email/Password for simplicity sake.

🛑 Assuming you already know how to add firebase to the vue.js project.

IMAGE ALT TEXT HERE

Enable Email/Password Authentication by going to Firebase Console → Firebase Authentication → Sign-in Method → Email/Password.

Here is the standard signup form with just an email and password.

Signup.vue

<template>
  <section class="ui centered grid" style="margin-top:30px;">
    <div class="column" style="max-width:450px;">
      <form class="ui segment large form">
        <div class="ui segment">
          <div class="field">
            <div class="ui left icon input large">
              <input type="text" placeholder="Enter your email" v-model="email" />
              <i class="ui icon user"></i>
            </div>
          </div>
          <div class="field">
            <div class="ui left icon input large">
              <input type="password" placeholder="Enter your password" v-model="password" />
              <i class="ui icon key"></i>
            </div>
          </div>
          <button class="ui button fluid large green" @click="signUpButtonPressed">Sign up</button>
        </div>
      </form>
      <router-link :to="{ name: 'Signin' }" tag="a" class="ui button basic">Log in</router-link>
    </div>
  </section>
</template>

<script>
export default {
  data() {
    return {
      email: "",
      password: "",
    };
  },
  methods: {
    signUpButtonPressed() {
    },
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

Import firebase at the top inside the script tag.

import firebase from 'firebase'
Enter fullscreen mode Exit fullscreen mode

Then, invoke createUserWithEmailAndPassword() method on the firebase object to create a new user inside the signUpButtonPressed().

firebase
  .auth()
  .createUserWithEmailAndPassword(this.email, this.password)
  .then(user => {
    console.log("Brand new user is added")
  })
  .catch(error => {
    console.log(error.message);
  });
Enter fullscreen mode Exit fullscreen mode

To show all the users' data on the Admin view, add user data to the Cloud Firestore when a new user account is created.

signUpButtonPressed() {
   firebase
      .auth()
      .createUserWithEmailAndPassword(this.email, this.password)
      .then(user => {
         this.addUserToDB(user);
      })
      .catch(error => {
         this.error = error.message;
      });
},

async addUserToDB({user}) {
   try {
      const db = firebase.firestore();
      _ = await db
         .collection("users")
         .doc(user.uid)
         .set({
            email: user.email,
            active:false
         });

   } catch (error) {
      console.log(error.message);
   }
}
Enter fullscreen mode Exit fullscreen mode

alt text

As you can see, I have created three user accounts from the signup.vue page.

Add User Roles

  • The Admin role will have access to all the drivers stored in the database and will be able to track their location at any time.
  • The Driver role will have access to read or write their own data and will be sending location updates to the database as they move.

Adding a role to each user should be done on the server side for security reasons and it can be done in two different ways using Cloud Function.

  • Using Auth Claims.
  • Adding read-only (from the client) collection that has user roles on the Cloud Firestore.

For simplicity's sake, I have added three user roles inside the roles collection with the same document ID as the user’s collection.

Two of them have isDriver : true field and one has the isAdmin : true field.

alt text

Firebase Security Rules

  • Only authenticated users can read or write data to the users collection.
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {   
    match /users/{uid} {
      allow read, write: if request.auth.uid == uid
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Only authenticated users can read to the roles collection but no one can write to it from the front-end.
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
   ...  
    match /roles/{uid} {
      allow read: if request.auth.uid == uid;
      allow write: if false;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Get all the user data when a signed-in user has an Admin role.

We can access the roles collection inside here using the get method by passing the database path to the isAdmin field.

 match /users/{uid} {
      allow read, write: if request.auth.uid == uid || get(/databases/$(database)/documents/roles/$(request.auth.uid)).data.isAdmin;
    }
Enter fullscreen mode Exit fullscreen mode

Want to learn more about Security Rules?
6 Must-Know Firestore Security Rules

Continue Reading ...

Discussion (0)