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
Infographics
Table Of Contents
- Create A New Firebase User
- Add User Roles
- Firebase Security Rules
- Sign In A User
- Navigation Auth Guards
- Driver View
- Get User Location Using watchPosition()
- Show Current Location On The Map
- Stop Location Updates
- Add Location Data To The Cloud Firestore
- Mock Multiple Driver’s Movement on the iOS Simulator
- Admin View: Show Map, Markers and InfoWindows
Project Setup
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">
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]">
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.
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>
Import firebase at the top inside the script tag.
import firebase from 'firebase'
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);
});
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);
}
}
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.
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
}
}
}
- 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;
}
}
}
- 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;
}
✅ Want to learn more about Security Rules?
6 Must-Know Firestore Security Rules
Top comments (0)