Merge branch 'main' into preferenceDropdownCSS
This commit is contained in:
@ -49,8 +49,8 @@ exports.postStationData = functions.https.onRequest((request, response) => {
|
|||||||
cors(request, response, () => {
|
cors(request, response, () => {
|
||||||
var batchWrite = db.batch();
|
var batchWrite = db.batch();
|
||||||
jsonData.forEach((doc) => {
|
jsonData.forEach((doc) => {
|
||||||
// append if the dartCodes hashset is empty or the current station is not present
|
// append if the dartCodes hashset is empty or the current station is not present, and ignoring positions of zero
|
||||||
if (dartCodes.size == 0 || !dartCodes.has(doc["StationCode"][0])) {
|
if ((dartCodes.size == 0 || !dartCodes.has(doc["StationCode"][0])) && !(doc["StationLongitude"] == 0 || doc["StationLatitude"] == 0)) {
|
||||||
doc["StationType"] = [stationTypeCode]
|
doc["StationType"] = [stationTypeCode]
|
||||||
var docID = db.collection('stations').doc(doc["StationCode"][0])
|
var docID = db.collection('stations').doc(doc["StationCode"][0])
|
||||||
batchWrite.set(docID, doc);
|
batchWrite.set(docID, doc);
|
||||||
@ -199,13 +199,26 @@ exports.postLiveTrainData = functions.https.onRequest((request, response) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
exports.securefunction = functions.https.onCall((data, context) => {
|
// secure function to fetch a user's filter preferences from the database
|
||||||
if (typeof context.auth === undefined) {
|
exports.getPreferences = functions.https.onCall((data, context) => {
|
||||||
// user not logged in
|
if (!context.auth) return "Error request is not verified"
|
||||||
return "User is not logged in"
|
return admin.firestore().collection('preferences').doc(context.auth.uid).get().then((preferences) => {
|
||||||
}
|
return preferences.data()
|
||||||
else {
|
})
|
||||||
// user logged in
|
})
|
||||||
return "User is logged in"
|
|
||||||
}
|
// secure function to set a user's filter preferences in the database
|
||||||
|
exports.postPreferences = functions.https.onCall((data, context) => {
|
||||||
|
if (!context.auth) return "Error request is not verified"
|
||||||
|
return admin.firestore().collection('preferences').doc(context.auth.uid).set({data}).then(() => {
|
||||||
|
return "Successfully saved preferences"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// secure function to delete a user's filter preferences from the database
|
||||||
|
exports.deletePreferences = functions.https.onCall((data, context) => {
|
||||||
|
if (!context.auth) return "Error request is not verified"
|
||||||
|
return admin.firestore().collection('preferences').doc(context.auth.uid).delete().then(() => {
|
||||||
|
return "Successfully deleted preferences"
|
||||||
|
})
|
||||||
})
|
})
|
6
package-lock.json
generated
6
package-lock.json
generated
@ -15,6 +15,7 @@
|
|||||||
"bootstrap-vue": "^2.23.1",
|
"bootstrap-vue": "^2.23.1",
|
||||||
"chart.js": "^4.2.1",
|
"chart.js": "^4.2.1",
|
||||||
"firebase": "^9.17.1",
|
"firebase": "^9.17.1",
|
||||||
|
"mosha-vue-toastify": "^1.0.23",
|
||||||
"ol": "^7.2.2",
|
"ol": "^7.2.2",
|
||||||
"vue": "^3.2.47",
|
"vue": "^3.2.47",
|
||||||
"vue-chartjs": "^5.2.0",
|
"vue-chartjs": "^5.2.0",
|
||||||
@ -1882,6 +1883,11 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mosha-vue-toastify": {
|
||||||
|
"version": "1.0.23",
|
||||||
|
"resolved": "https://registry.npmjs.org/mosha-vue-toastify/-/mosha-vue-toastify-1.0.23.tgz",
|
||||||
|
"integrity": "sha512-K9fij3e3H+E/Lj82ISrgmyKrtM5RNmtZC/KG/KH47+oZGmzAkN/Zuz39kBdT/Mp8OxaHuIWQntEUMP+HdmK1xA=="
|
||||||
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
"bootstrap-vue": "^2.23.1",
|
"bootstrap-vue": "^2.23.1",
|
||||||
"chart.js": "^4.2.1",
|
"chart.js": "^4.2.1",
|
||||||
"firebase": "^9.17.1",
|
"firebase": "^9.17.1",
|
||||||
|
"mosha-vue-toastify": "^1.0.23",
|
||||||
"ol": "^7.2.2",
|
"ol": "^7.2.2",
|
||||||
"vue": "^3.2.47",
|
"vue": "^3.2.47",
|
||||||
"vue-chartjs": "^5.2.0",
|
"vue-chartjs": "^5.2.0",
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import app from "../api/firebase"
|
import app from "../api/firebase"
|
||||||
import { getAuth, onAuthStateChanged, signOut } from "firebase/auth"
|
import { getAuth, onAuthStateChanged, signOut } from "firebase/auth"
|
||||||
|
import { store } from '../store/store'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Navbar",
|
name: "Navbar",
|
||||||
@ -49,6 +50,7 @@ export default {
|
|||||||
const auth = getAuth(app);
|
const auth = getAuth(app);
|
||||||
onAuthStateChanged(auth, (user) => {
|
onAuthStateChanged(auth, (user) => {
|
||||||
user ? this.isLoggedIn = true : this.isLoggedIn = false
|
user ? this.isLoggedIn = true : this.isLoggedIn = false
|
||||||
|
store.setLoginStatus(this.isLoggedIn)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -6,30 +6,31 @@
|
|||||||
<h3>Enter your current password to edit account settings</h3>
|
<h3>Enter your current password to edit account settings</h3>
|
||||||
<input type="password" v-model="currentPassword" placeholder="Enter existing password">
|
<input type="password" v-model="currentPassword" placeholder="Enter existing password">
|
||||||
<h3>Send a password reset email</h3>
|
<h3>Send a password reset email</h3>
|
||||||
<input @click="resetPasswordEmail" type="submit" name="" value="Send Password reset email">
|
<input @click="resetPasswordEmail()" type="submit" name="" value="Send Password reset email">
|
||||||
|
|
||||||
<h3>Change email</h3>
|
<h3>Change email</h3>
|
||||||
<input type="email" v-model="newEmail" aria-describedby="emailHelp" placeholder="Enter new email">
|
<input type="email" v-model="newEmail" aria-describedby="emailHelp" placeholder="Enter new email">
|
||||||
<input @click="updateUserEmail" type="submit" name="" value="Update Email">
|
<input @click="updateUserEmail()" type="submit" name="" value="Update Email">
|
||||||
|
|
||||||
<h3>Change password</h3>
|
<h3>Change password</h3>
|
||||||
<input type="password" v-model="newPassword" placeholder="Enter new password">
|
<input type="password" v-model="newPassword" placeholder="Enter new password">
|
||||||
<input @click="updateUserPassword" type="submit" name="" value="Update Password">
|
<input @click="updateUserPassword()" type="submit" name="" value="Update Password">
|
||||||
|
|
||||||
<h3>Delete account</h3>
|
<h3>Delete account</h3>
|
||||||
<input @click="deleteUserAccount" type="submit" name="" value="Delete Account">
|
<input @click="deleteUserAccount()" type="submit" name="" value="Delete Account">
|
||||||
</div>
|
|
||||||
|
|
||||||
<p v-if="missingCredentials">Missing credentials to complete this action</p>
|
<h3>Delete filter preferences data</h3>
|
||||||
<p v-if="displayFirebaseSuccessMsg">{{ FirebaseSuccessMsg }}</p>
|
<button @click="deleteUserPreferences()">Delete preferences</button>
|
||||||
<p v-if="displayFirebaseError">{{ FirebaseError }}</p>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Navbar from '../components/Navbar.vue'
|
|
||||||
import app from '../api/firebase'
|
|
||||||
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions"
|
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions"
|
||||||
import { getAuth, updateEmail, updatePassword, deleteUser, reauthenticateWithCredential, EmailAuthProvider, sendPasswordResetEmail } from "firebase/auth";
|
import { getAuth, updateEmail, updatePassword, deleteUser, reauthenticateWithCredential, EmailAuthProvider, sendPasswordResetEmail } from "firebase/auth";
|
||||||
|
import { createToast } from 'mosha-vue-toastify';
|
||||||
|
import 'mosha-vue-toastify/dist/style.css'
|
||||||
|
import Navbar from '../components/Navbar.vue'
|
||||||
|
import app from '../api/firebase'
|
||||||
const auth = getAuth();
|
const auth = getAuth();
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -40,52 +41,48 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
const toast = () => {
|
||||||
|
createToast(this.toastMessage, {
|
||||||
|
hideProgressBar: true,
|
||||||
|
timeout: 4000,
|
||||||
|
toastBackgroundColor: this.toastBackground
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: null,
|
user: null,
|
||||||
newEmail: "",
|
newEmail: "",
|
||||||
newPassword: "",
|
newPassword: "",
|
||||||
currentPassword: "",
|
currentPassword: "",
|
||||||
displayFirebaseSuccessMsg: false,
|
toastMessage: "",
|
||||||
FirebaseSuccessMsg: "",
|
toastBackground: "",
|
||||||
displayFirebaseError: false,
|
|
||||||
FirebaseError: "",
|
|
||||||
reAuthSuccessful: false,
|
reAuthSuccessful: false,
|
||||||
missingCredentials: false
|
toast
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.user = auth.currentUser
|
this.user = auth.currentUser
|
||||||
const functions = getFunctions(app)
|
|
||||||
let host = window.location.hostname
|
|
||||||
if (host === '127.0.0.1' || host === 'localhost') {
|
|
||||||
connectFunctionsEmulator(functions, host, 5001);
|
|
||||||
}
|
|
||||||
const secureFunction = httpsCallable(functions, 'securefunction')
|
|
||||||
secureFunction().then((response) => {
|
|
||||||
console.log(response);
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
showToast(message, backgroundColour) {
|
||||||
|
this.toastMessage = message
|
||||||
|
this.toastBackground = backgroundColour
|
||||||
|
this.toast()
|
||||||
|
},
|
||||||
|
|
||||||
async authenticateUser(password) {
|
async authenticateUser(password) {
|
||||||
var credential = await EmailAuthProvider.credential(user.email, password)
|
var credential = await EmailAuthProvider.credential(this.user.email, password)
|
||||||
await reauthenticateWithCredential(user, credential).then(() => {
|
await reauthenticateWithCredential(this.user, credential).then(() => {
|
||||||
this.reAuthSuccessful = true
|
this.reAuthSuccessful = true
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.reAuthSuccessful = false
|
this.reAuthSuccessful = false
|
||||||
this.FirebaseError = error.message
|
this.showToast(error.message, "red")
|
||||||
this.displayFirebaseError = true
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
resetMessages() {
|
|
||||||
this.missingCredentials = false
|
|
||||||
this.displayFirebaseError = false
|
|
||||||
this.displayFirebaseSuccessMsg = false
|
|
||||||
},
|
|
||||||
|
|
||||||
resetCredentials() {
|
resetCredentials() {
|
||||||
this.newEmail = ""
|
this.newEmail = ""
|
||||||
this.newPassword = ""
|
this.newPassword = ""
|
||||||
@ -94,75 +91,94 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateUserEmail() {
|
updateUserEmail() {
|
||||||
this.resetMessages()
|
|
||||||
if (!this.newEmail || !this.currentPassword) {
|
if (!this.newEmail || !this.currentPassword) {
|
||||||
this.missingCredentials = true
|
this.showToast("Missing password input", "red")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.authenticateUser(this.currentPassword).then(() => {
|
this.authenticateUser(this.currentPassword).then(() => {
|
||||||
if (!this.reAuthSuccessful) return
|
if (!this.reAuthSuccessful) return
|
||||||
updateEmail(this.user, this.newEmail).then(() => {
|
updateEmail(this.user, this.newEmail).then(() => {
|
||||||
// might need to reset user here
|
|
||||||
this.resetCredentials()
|
this.resetCredentials()
|
||||||
this.FirebaseSuccessMsg = "Email updated"
|
this.showToast("Email successfully updated", "green")
|
||||||
this.displayFirebaseSuccessMsg = true
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.FirebaseError = error.message
|
this.showToast(error.message, "red")
|
||||||
this.displayFirebaseError = true
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
updateUserPassword() {
|
updateUserPassword() {
|
||||||
this.resetMessages()
|
|
||||||
if (!this.newPassword || !this.currentPassword) {
|
if (!this.newPassword || !this.currentPassword) {
|
||||||
this.missingCredentials = true
|
this.showToast("Missing password input", "red")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.authenticateUser(this.currentPassword).then(() => {
|
this.authenticateUser(this.currentPassword).then(() => {
|
||||||
if (!this.reAuthSuccessful) return
|
if (!this.reAuthSuccessful) return
|
||||||
updatePassword(this.user, this.newPassword).then(() => {
|
updatePassword(this.user, this.newPassword).then(() => {
|
||||||
this.resetCredentials()
|
this.resetCredentials()
|
||||||
this.FirebaseSuccessMsg = "Password updated"
|
this.showToast("Password successfully updated", "green")
|
||||||
this.displayFirebaseSuccessMsg = true
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.FirebaseError = error.message
|
this.showToast(error.message, "red")
|
||||||
this.displayFirebaseError = true
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteUserAccount() {
|
deleteUserAccount() {
|
||||||
this.resetMessages()
|
|
||||||
if (!this.currentPassword) {
|
if (!this.currentPassword) {
|
||||||
this.missingCredentials = true
|
this.showToast("Missing password input", "red")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.authenticateUser(this.currentPassword).then(() => {
|
this.authenticateUser(this.currentPassword).then(() => {
|
||||||
if (!this.reAuthSuccessful) return
|
if (!this.reAuthSuccessful) return
|
||||||
deleteUser(this.user).then(() => {
|
deleteUser(this.user).then(() => {
|
||||||
this.resetCredentials()
|
this.resetCredentials()
|
||||||
this.FirebaseSuccessMsg = "Account deleted"
|
this.showToast("Account successfully deleted", "green")
|
||||||
this.displayFirebaseSuccessMsg = true
|
|
||||||
this.$router.push({path:'/'})
|
this.$router.push({path:'/'})
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.FirebaseError = error.message
|
this.showToast(error.message, "red")
|
||||||
this.displayFirebaseError = true
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
resetPasswordEmail() {
|
resetPasswordEmail() {
|
||||||
sendPasswordResetEmail(auth, this.user.email).then(() => {
|
sendPasswordResetEmail(auth, this.user.email).then(() => {
|
||||||
this.FirebaseSuccessMsg = "Reset password email sent"
|
this.showToast("Reset password email sent", "green")
|
||||||
this.displayFirebaseSuccessMsg = true
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.FirebaseError = error.message
|
this.showToast(error.message, "red")
|
||||||
this.displayFirebaseError = true
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteUserPreferences() {
|
||||||
|
if (!this.currentPassword) {
|
||||||
|
this.showToast("Missing password input", "red")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.authenticateUser(this.currentPassword).then(() => {
|
||||||
|
if (!this.reAuthSuccessful) return
|
||||||
|
const functions = getFunctions(app)
|
||||||
|
let host = window.location.hostname
|
||||||
|
if (host === '127.0.0.1' || host === 'localhost') {
|
||||||
|
connectFunctionsEmulator(functions, host, 5001);
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletePreferencesData = httpsCallable(functions, 'deletePreferences')
|
||||||
|
deletePreferencesData().then(() => {
|
||||||
|
this.resetCredentials()
|
||||||
|
this.showToast("Successfully deleted filter preferences", "green")
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.showToast(error.message, "red")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.showToast(error.message, "red")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,6 @@
|
|||||||
<a @click="forgotPassword = !forgotPassword; this.email = ''">Go back</a>
|
<a @click="forgotPassword = !forgotPassword; this.email = ''">Go back</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p v-if="displayFirebaseError">{{ FirebaseError }}</p>
|
|
||||||
<p v-if="displayFirebaseSuccessMsg">{{ FirebaseSuccessMsg }}</p>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -36,6 +30,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import app from '../api/firebase';
|
import app from '../api/firebase';
|
||||||
import { getAuth, signInWithEmailAndPassword, sendPasswordResetEmail } from "firebase/auth"
|
import { getAuth, signInWithEmailAndPassword, sendPasswordResetEmail } from "firebase/auth"
|
||||||
|
import { createToast } from 'mosha-vue-toastify';
|
||||||
|
import 'mosha-vue-toastify/dist/style.css'
|
||||||
import Navbar from '../components/Navbar.vue'
|
import Navbar from '../components/Navbar.vue'
|
||||||
const auth = getAuth()
|
const auth = getAuth()
|
||||||
|
|
||||||
@ -43,14 +39,21 @@ export default {
|
|||||||
name: "LoginPage",
|
name: "LoginPage",
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
const toast = () => {
|
||||||
|
createToast(this.toastMessage, {
|
||||||
|
hideProgressBar: true,
|
||||||
|
timeout: 4000,
|
||||||
|
toastBackgroundColor: this.toastBackground
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
displayFirebaseError: false,
|
toastMessage: "",
|
||||||
FirebaseError: "",
|
toastBackground: "",
|
||||||
displayFirebaseSuccessMsg: false,
|
forgotPassword: false,
|
||||||
FirebaseSuccessMsg: "",
|
toast
|
||||||
forgotPassword: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -59,29 +62,30 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
showToast(message, backgroundColour) {
|
||||||
|
this.toastMessage = message
|
||||||
|
this.toastBackground = backgroundColour
|
||||||
|
this.toast()
|
||||||
|
},
|
||||||
|
|
||||||
login() {
|
login() {
|
||||||
this.displayFirebaseError = false
|
|
||||||
const auth = getAuth(app)
|
const auth = getAuth(app)
|
||||||
signInWithEmailAndPassword(auth, this.email, this.password)
|
signInWithEmailAndPassword(auth, this.email, this.password).then(() => {
|
||||||
.then((userCredential) => {
|
this.showToast("Logged in successfully", "green")
|
||||||
const user = userCredential.user
|
this.$router.push({path:'/'})
|
||||||
this.$router.push({path:'/account'})
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.FirebaseError = error.message
|
this.showToast(error.message, "red")
|
||||||
this.displayFirebaseError = true
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
resetPasswordEmail() {
|
resetPasswordEmail() {
|
||||||
sendPasswordResetEmail(auth, this.email).then(() => {
|
sendPasswordResetEmail(auth, this.email).then(() => {
|
||||||
this.FirebaseSuccessMsg = "Reset password email sent"
|
this.showToast("Reset password email sent", "green")
|
||||||
this.displayFirebaseSuccessMsg = true
|
|
||||||
this.email = ""
|
this.email = ""
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.FirebaseError = error.message
|
this.showToast(error.message, "red")
|
||||||
this.displayFirebaseError = true
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<button v-if="store.loggedIn" @click="postPreferences()">Save Preferences</button>
|
||||||
|
|
||||||
<transition id="sidebar" name="slideLeft">
|
<transition id="sidebar" name="slideLeft">
|
||||||
<div v-if="store.displaySelectedTrain && store.selectedTrain">
|
<div v-if="store.displaySelectedTrain && store.selectedTrain">
|
||||||
@ -67,7 +68,7 @@
|
|||||||
|
|
||||||
<!-- train overlay -->
|
<!-- train overlay -->
|
||||||
<template v-for="coordinate, i in trainCoordinates" :position="inline-block">
|
<template v-for="coordinate, i in trainCoordinates" :position="inline-block">
|
||||||
<ol-overlay v-if="showTrains[i]" :position="coordinate" :positioning="center-center" :offset="[-14,-16]">
|
<ol-overlay v-if="showTrains[i]" :position="coordinate" :offset="[-14,-16]">
|
||||||
<div class="overlay-content" @click="getSelectedTrain(i)">
|
<div class="overlay-content" @click="getSelectedTrain(i)">
|
||||||
<div v-if="getTrainType(i) === 'DART'">
|
<div v-if="getTrainType(i) === 'DART'">
|
||||||
<img v-if="isTrainRunning(i) && isTrainLate(i)" src="../assets/red-train-tram-solid.png" class="trainMapIcon" alt="Late DART Icon">
|
<img v-if="isTrainRunning(i) && isTrainLate(i)" src="../assets/red-train-tram-solid.png" class="trainMapIcon" alt="Late DART Icon">
|
||||||
@ -85,7 +86,7 @@
|
|||||||
|
|
||||||
<!-- station overlay -->
|
<!-- station overlay -->
|
||||||
<template v-for="coordinate, i in stationCoordinates" :position="inline-block">
|
<template v-for="coordinate, i in stationCoordinates" :position="inline-block">
|
||||||
<ol-overlay v-if="showStations[i]" :position="coordinate" :positioning="center-center" :offset="[-14,-16]">
|
<ol-overlay v-if="showStations[i]" :position="coordinate" :offset="[-14,-16]">
|
||||||
<div class="overlay-content" @click="getSelectedStation(i)">
|
<div class="overlay-content" @click="getSelectedStation(i)">
|
||||||
<img src="../assets/station.png" class="stationMapIcon" alt="Station Icon">
|
<img src="../assets/station.png" class="stationMapIcon" alt="Station Icon">
|
||||||
</div>
|
</div>
|
||||||
@ -103,9 +104,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { store } from '../store/store';
|
import { store } from '../store/store';
|
||||||
import { ref } from 'vue';
|
import { fromLonLat } from 'ol/proj.js';
|
||||||
import { fromLonLat, toLonLat } from 'ol/proj.js';
|
|
||||||
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions";
|
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions";
|
||||||
|
import { createToast } from 'mosha-vue-toastify';
|
||||||
|
import 'mosha-vue-toastify/dist/style.css'
|
||||||
import app from '../api/firebase';
|
import app from '../api/firebase';
|
||||||
import Navbar from '../components/Navbar.vue';
|
import Navbar from '../components/Navbar.vue';
|
||||||
import MarqueeText from 'vue-marquee-text-component';
|
import MarqueeText from 'vue-marquee-text-component';
|
||||||
@ -116,60 +118,44 @@ export default {
|
|||||||
name: "MapPage",
|
name: "MapPage",
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
const center = ref(fromLonLat([-7.5029786, 53.4494762]));
|
const toast = () => {
|
||||||
const projection = ref('EPSG:3857');
|
createToast(this.toastMessage, {
|
||||||
const zoom = ref(7);
|
hideProgressBar: true,
|
||||||
const rotation = ref(0);
|
timeout: 4000,
|
||||||
const radius = ref(10);
|
toastBackgroundColor: this.toastBackground
|
||||||
const strokeWidth = ref(1);
|
})
|
||||||
const strokeColor = ref('black');
|
}
|
||||||
const fillColor = ref('red');
|
|
||||||
|
|
||||||
let showTrains = [];
|
return {
|
||||||
let showStations = [];
|
center: fromLonLat([-7.5029786, 53.4494762]),
|
||||||
|
projection: 'EPSG:3857',
|
||||||
|
zoom: 7,
|
||||||
|
rotation: 0,
|
||||||
|
|
||||||
let showMainlandStations = true;
|
showTrains: [],
|
||||||
let showDARTStations = true;
|
showStations: [],
|
||||||
let showLate = true;
|
trainCoordinates: [],
|
||||||
let showOnTime = true;
|
stationCoordinates: [],
|
||||||
let showEarly = true;
|
allTrains: {},
|
||||||
let showMainland = true;
|
allStations: {},
|
||||||
let showDART = true;
|
publicMessages: [],
|
||||||
let showRunning = true;
|
isPaused: false,
|
||||||
let showTerminated = true;
|
store,
|
||||||
let showNotYetRunning = true;
|
|
||||||
|
|
||||||
return {
|
toastMessage: "",
|
||||||
center,
|
toastBackground: "",
|
||||||
projection,
|
toast,
|
||||||
zoom,
|
|
||||||
rotation,
|
|
||||||
radius,
|
|
||||||
strokeWidth,
|
|
||||||
strokeColor,
|
|
||||||
fillColor,
|
|
||||||
|
|
||||||
showTrains: [],
|
showMainlandStations: true,
|
||||||
showStations: [],
|
showDARTStations: true,
|
||||||
trainCoordinates: [],
|
showLate: true,
|
||||||
stationCoordinates: [],
|
showOnTime: true,
|
||||||
allTrains: {},
|
showMainland: true,
|
||||||
allStations: {},
|
showDART: true,
|
||||||
publicMessages: [],
|
showRunning: true,
|
||||||
isPaused: false,
|
showTerminated: true,
|
||||||
store,
|
showNotYetRunning: true,
|
||||||
|
}
|
||||||
showMainlandStations,
|
|
||||||
showDARTStations,
|
|
||||||
showLate,
|
|
||||||
showOnTime,
|
|
||||||
showEarly,
|
|
||||||
showMainland,
|
|
||||||
showDART,
|
|
||||||
showRunning,
|
|
||||||
showTerminated,
|
|
||||||
showNotYetRunning
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
@ -187,38 +173,101 @@ export default {
|
|||||||
else {
|
else {
|
||||||
this.getTrainAndStationData();
|
this.getTrainAndStationData();
|
||||||
}
|
}
|
||||||
|
|
||||||
// request new data every 60 seconds
|
// request new data every 60 seconds
|
||||||
// window.setInterval(this.getLiveTrainData, 60000);
|
// window.setInterval(this.getTrainAndStationData, 60000);
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
showToast(message, backgroundColour) {
|
||||||
|
this.toastMessage = message
|
||||||
|
this.toastBackground = backgroundColour
|
||||||
|
this.toast()
|
||||||
|
},
|
||||||
|
|
||||||
|
getPreferences() {
|
||||||
|
if (!store.loggedIn) return
|
||||||
|
const functions = getFunctions(app);
|
||||||
|
let host = window.location.hostname
|
||||||
|
if (host === '127.0.0.1' || host == 'localhost') {
|
||||||
|
connectFunctionsEmulator(functions, host, 5001);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPreferencesData = httpsCallable(functions, 'getPreferences')
|
||||||
|
getPreferencesData().then((response) => {
|
||||||
|
if (response.data.data) {
|
||||||
|
this.showMainlandStations = response.data.data["showMainlandStations"]
|
||||||
|
this.showDARTStations = response.data.data["showDARTStations"]
|
||||||
|
this.showLate = response.data.data["showLate"]
|
||||||
|
this.showOnTime = response.data.data["showOnTime"]
|
||||||
|
this.showMainland = response.data.data["showMainland"]
|
||||||
|
this.showDART = response.data.data["showDART"]
|
||||||
|
this.showRunning = response.data.data["showRunning"]
|
||||||
|
this.showTerminated = response.data.data["showTerminated"]
|
||||||
|
this.showNotYetRunning = response.data.data["showNotYetRunning"]
|
||||||
|
|
||||||
|
// update the map with the user's preferences
|
||||||
|
this.decideShowStations()
|
||||||
|
this.decideShowTrains()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error.message)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
postPreferences() {
|
||||||
|
if (!store.loggedIn) return
|
||||||
|
let preferences = {
|
||||||
|
"showMainlandStations": this.showMainlandStations,
|
||||||
|
"showDARTStations": this.showDARTStations,
|
||||||
|
"showLate": this.showLate,
|
||||||
|
"showOnTime": this.showOnTime,
|
||||||
|
"showMainland": this.showMainland,
|
||||||
|
"showDART": this.showDART,
|
||||||
|
"showRunning": this.showRunning,
|
||||||
|
"showTerminated": this.showTerminated,
|
||||||
|
"showNotYetRunning": this.showNotYetRunning
|
||||||
|
}
|
||||||
|
|
||||||
|
const functions = getFunctions(app);
|
||||||
|
let host = window.location.hostname
|
||||||
|
if (host === '127.0.0.1' || host == 'localhost') {
|
||||||
|
connectFunctionsEmulator(functions, host, 5001);
|
||||||
|
}
|
||||||
|
|
||||||
|
const postPreferencesData = httpsCallable(functions, 'postPreferences')
|
||||||
|
postPreferencesData(preferences).then(() => {
|
||||||
|
this.showToast("Saved preferences successfully", "green")
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.showToast(error.message, "red")
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
// method to determine whether or not to show each train
|
// method to determine whether or not to show each train
|
||||||
decideShowTrains() {
|
decideShowTrains() {
|
||||||
for (let i = 0; i < this.showTrains.length; i++) {
|
for (var i=0; i<this.showTrains.length; i++) {
|
||||||
// determine whether or not the tain is a DART or not
|
let isDART = this.getTrainType(i) == "DART";
|
||||||
let isDART = this.getTrainType(i) == "DART";
|
if ((this.showRunning && this.allTrains[i]["TrainStatus"][0] == "R") || (this.showTerminated && this.allTrains[i]["TrainStatus"][0] == "T") || this.showNotYetRunning && this.allTrains[i]["TrainStatus"][0] == "N") {
|
||||||
|
if ((this.showDART && isDART) || (this.showMainland && !isDART)) {
|
||||||
if ((this.showRunning && this.allTrains[i]["TrainStatus"][0] == "R") || (this.showTerminated && this.allTrains[i]["TrainStatus"][0] == "T") || this.showNotYetRunning && this.allTrains[i]["TrainStatus"][0] == "N") {
|
this.showTrains[i] = (this.showLate && this.isTrainLate(i)) || (this.showOnTime && !this.isTrainLate(i));
|
||||||
if ((this.showDART && isDART) || (this.showMainland && !isDART)) {
|
}
|
||||||
this.showTrains[i] = (this.showLate && this.isTrainLate(i)) || (this.showOnTime && !this.isTrainLate(i)); // || (this.showMainland && !isDART) || (this.showDART && isDART);
|
else {
|
||||||
}
|
this.showTrains[i] = false;
|
||||||
else {
|
}
|
||||||
this.showTrains[i] = false;
|
}
|
||||||
}
|
else {
|
||||||
}
|
this.showTrains[i] = false;
|
||||||
else {
|
}
|
||||||
this.showTrains[i] = false;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// method to determine whether or not to show each station
|
// method to determine whether or not to show each station
|
||||||
decideShowStations() {
|
decideShowStations() {
|
||||||
for (let i = 0; i < this.showStations.length; i++) {
|
for (var i=0; i<this.showStations.length; i++) {
|
||||||
let isDARTStation = this.allStations[i]["StationType"][0] == "DART";
|
let isDARTStation = this.getStationType(i) == "DART";
|
||||||
this.showStations[i] = (this.showDARTStations && isDARTStation) || (this.showMainlandStations && !isDARTStation);
|
this.showStations[i] = (this.showDARTStations && isDARTStation) || (this.showMainlandStations && !isDARTStation);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// method to display a selected train
|
// method to display a selected train
|
||||||
@ -252,12 +301,8 @@ export default {
|
|||||||
|
|
||||||
// method to determine whether or not a selected train is running
|
// method to determine whether or not a selected train is running
|
||||||
isTrainRunning(i) {
|
isTrainRunning(i) {
|
||||||
if (this.allTrains[i]["TrainStatus"][0] == "R") {
|
if (this.allTrains[i]["TrainStatus"][0] == "R") return true;
|
||||||
return true;
|
else return false;
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// method that returns the type of train (either "Train" or "DART")
|
// method that returns the type of train (either "Train" or "DART")
|
||||||
@ -265,6 +310,11 @@ export default {
|
|||||||
return this.allTrains[i]["TrainType"][0];
|
return this.allTrains[i]["TrainType"][0];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// method that returns the type of station (either "Train" or "DART")
|
||||||
|
getStationType(i) {
|
||||||
|
return this.allStations[i]["StationType"][0]
|
||||||
|
},
|
||||||
|
|
||||||
// method to fetch live train and station data from the database
|
// method to fetch live train and station data from the database
|
||||||
getTrainAndStationData() {
|
getTrainAndStationData() {
|
||||||
const functions = getFunctions(app);
|
const functions = getFunctions(app);
|
||||||
@ -283,15 +333,16 @@ export default {
|
|||||||
try {
|
try {
|
||||||
if (!response.data) throw new Error("Error fetching live train data from the database");
|
if (!response.data) throw new Error("Error fetching live train data from the database");
|
||||||
var insights = {
|
var insights = {
|
||||||
"totalNumTrains": 0,
|
"totalNumTrains": 0,
|
||||||
"numRunningTrains": 0,
|
"numRunningTrains": 0,
|
||||||
"numLateRunningTrains": 0,
|
"numLateRunningTrains": 0,
|
||||||
"numTrains": 0,
|
"numTrains": 0,
|
||||||
"numDarts": 0,
|
"numDarts": 0,
|
||||||
"totalNumStations": 0,
|
"totalNumStations": 0,
|
||||||
"numTrainStations": 0,
|
"numTrainStations": 0,
|
||||||
"numDartStations": 0
|
"numDartStations": 0
|
||||||
};
|
};
|
||||||
|
|
||||||
var unorderedTrains = [];
|
var unorderedTrains = [];
|
||||||
var currentMessages = [];
|
var currentMessages = [];
|
||||||
var latest = null;
|
var latest = null;
|
||||||
@ -303,13 +354,11 @@ export default {
|
|||||||
for (var i=0; i<response.data.length; i++) {
|
for (var i=0; i<response.data.length; i++) {
|
||||||
let train = response.data[i];
|
let train = response.data[i];
|
||||||
this.allTrains[i] = train;
|
this.allTrains[i] = train;
|
||||||
|
this.trainCoordinates[i] = fromLonLat([train["TrainLongitude"][0], train["TrainLatitude"][0]])
|
||||||
// filling showTrains witht the default value true
|
|
||||||
this.showTrains[i] = true;
|
|
||||||
|
|
||||||
this.trainCoordinates[i] = ref(fromLonLat([train["TrainLongitude"][0], train["TrainLatitude"][0]]))
|
|
||||||
insights["totalNumTrains"] += 1
|
insights["totalNumTrains"] += 1
|
||||||
|
|
||||||
|
// filling showTrains with the default value - true
|
||||||
|
this.showTrains[i] = true;
|
||||||
if (train["TrainType"][0] == "Train") insights["numTrains"] += 1;
|
if (train["TrainType"][0] == "Train") insights["numTrains"] += 1;
|
||||||
else if (train["TrainType"][0] == "DART") insights["numDarts"] += 1;
|
else if (train["TrainType"][0] == "DART") insights["numDarts"] += 1;
|
||||||
|
|
||||||
@ -340,7 +389,6 @@ export default {
|
|||||||
// train is early or ontime
|
// train is early or ontime
|
||||||
else {
|
else {
|
||||||
if (!earliest) earliest = train;
|
if (!earliest) earliest = train;
|
||||||
|
|
||||||
// check for a new earliest train (early trains are -x mins late)
|
// check for a new earliest train (early trains are -x mins late)
|
||||||
if (num < currEarliestTime) {
|
if (num < currEarliestTime) {
|
||||||
earliest = train;
|
earliest = train;
|
||||||
@ -365,26 +413,27 @@ export default {
|
|||||||
const getStationData = httpsCallable(functions, 'getStationData');
|
const getStationData = httpsCallable(functions, 'getStationData');
|
||||||
getStationData().then((response) => {
|
getStationData().then((response) => {
|
||||||
if (!response.data) throw new Error("Error fetching station from the database");
|
if (!response.data) throw new Error("Error fetching station from the database");
|
||||||
|
|
||||||
for (var i=0; i<response.data.length; i++) {
|
for (var i=0; i<response.data.length; i++) {
|
||||||
let station = response.data[i];
|
let station = response.data[i];
|
||||||
this.allStations[i] = station;
|
this.allStations[i] = station;
|
||||||
|
this.stationCoordinates[i] = fromLonLat([station["StationLongitude"][0], station["StationLatitude"][0]])
|
||||||
|
insights["totalNumStations"] += 1
|
||||||
|
|
||||||
// setting the station to show on the map by default - true
|
// setting the station to show on the map by default - true
|
||||||
this.showStations[i] = true;
|
this.showStations[i] = true;
|
||||||
|
|
||||||
this.stationCoordinates[i] = ref(fromLonLat([station["StationLongitude"][0], station["StationLatitude"][0]]))
|
|
||||||
insights["totalNumStations"] += 1
|
|
||||||
|
|
||||||
if (station["StationType"][0] == "DART") insights["numDartStations"] += 1;
|
if (station["StationType"][0] == "DART") insights["numDartStations"] += 1;
|
||||||
else if (station["StationType"][0] == "Train") insights["numTrainStations"] += 1;
|
else if (station["StationType"][0] == "Train") insights["numTrainStations"] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
store.setInsights(insights);
|
store.setInsights(insights);
|
||||||
loader.hide();
|
loader.hide();
|
||||||
|
// request the user's preferences
|
||||||
|
this.getPreferences()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.log(error)
|
console.log(error.message)
|
||||||
loader.hide();
|
loader.hide();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -397,12 +446,11 @@ export default {
|
|||||||
if (host === '127.0.0.1' || host === 'localhost') {
|
if (host === '127.0.0.1' || host === 'localhost') {
|
||||||
connectFunctionsEmulator(functions, host, 5001);
|
connectFunctionsEmulator(functions, host, 5001);
|
||||||
}
|
}
|
||||||
// post live train data
|
|
||||||
const postTrainData = httpsCallable(functions, 'postLiveTrainData');
|
const postTrainData = httpsCallable(functions, 'postLiveTrainData');
|
||||||
postTrainData().then((response) => {
|
postTrainData().then(() => {
|
||||||
// post station data
|
|
||||||
const postStationData = httpsCallable(functions, 'postStationData');
|
const postStationData = httpsCallable(functions, 'postStationData');
|
||||||
postStationData().then((reponse) => {
|
postStationData().then(() => {
|
||||||
this.getTrainAndStationData()
|
this.getTrainAndStationData()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -19,17 +19,28 @@
|
|||||||
<script>
|
<script>
|
||||||
import app from '../api/firebase';
|
import app from '../api/firebase';
|
||||||
import {getAuth, createUserWithEmailAndPassword} from "firebase/auth"
|
import {getAuth, createUserWithEmailAndPassword} from "firebase/auth"
|
||||||
|
import { createToast } from 'mosha-vue-toastify';
|
||||||
|
import 'mosha-vue-toastify/dist/style.css'
|
||||||
import Navbar from '../components/Navbar.vue'
|
import Navbar from '../components/Navbar.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SignupPage",
|
name: "SignupPage",
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
const toast = () => {
|
||||||
|
createToast(this.toastMessage, {
|
||||||
|
hideProgressBar: true,
|
||||||
|
timeout: 4000,
|
||||||
|
toastBackgroundColor: this.toastBackground
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
displayFirebaseError: false,
|
toastMessage: "",
|
||||||
FirebaseError: ""
|
toastBackground: "",
|
||||||
|
toast
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -38,17 +49,21 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
showToast(message, backgroundColour) {
|
||||||
|
this.toastMessage = message
|
||||||
|
this.toastBackground = backgroundColour
|
||||||
|
this.toast()
|
||||||
|
},
|
||||||
|
|
||||||
signup() {
|
signup() {
|
||||||
this.displayFirebaseError = false;
|
this.displayFirebaseError = false;
|
||||||
const auth = getAuth(app)
|
const auth = getAuth(app)
|
||||||
createUserWithEmailAndPassword(auth, this.email, this.password)
|
createUserWithEmailAndPassword(auth, this.email, this.password).then(() => {
|
||||||
.then((userCredential) => {
|
this.showToast("Signed up successfully", "green")
|
||||||
const user = userCredential.user
|
this.$router.push({path:'/'})
|
||||||
this.$router.push({path:'/account'})
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.FirebaseError = error.message
|
this.showToast(error.message, "red")
|
||||||
this.displayFirebaseError = true
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import {getAuth, onAuthStateChanged} from "firebase/auth"
|
|||||||
import app from '../api/firebase';
|
import app from '../api/firebase';
|
||||||
|
|
||||||
function isAuth(to, from, next) {
|
function isAuth(to, from, next) {
|
||||||
console.log("Checking auth")
|
|
||||||
const auth = getAuth(app)
|
const auth = getAuth(app)
|
||||||
onAuthStateChanged(auth, (user) => {
|
onAuthStateChanged(auth, (user) => {
|
||||||
// user is logged in, continue to page
|
// user is logged in, continue to page
|
||||||
|
@ -10,6 +10,7 @@ export const store = reactive({
|
|||||||
rawData: {},
|
rawData: {},
|
||||||
displaySelectedTrain: false,
|
displaySelectedTrain: false,
|
||||||
displayedSelectedStation: false,
|
displayedSelectedStation: false,
|
||||||
|
loggedIn: false,
|
||||||
|
|
||||||
setInsights(insights) {
|
setInsights(insights) {
|
||||||
this.insights = insights
|
this.insights = insights
|
||||||
@ -49,5 +50,9 @@ export const store = reactive({
|
|||||||
|
|
||||||
setDisplaySelectedStation(bool) {
|
setDisplaySelectedStation(bool) {
|
||||||
this.displaySelectedStation = bool
|
this.displaySelectedStation = bool
|
||||||
|
},
|
||||||
|
|
||||||
|
setLoginStatus(bool) {
|
||||||
|
this.loggedIn = bool
|
||||||
}
|
}
|
||||||
})
|
})
|
Reference in New Issue
Block a user