Merge branch 'main' into preferenceDropdownCSS

This commit is contained in:
2023-03-16 15:55:18 +00:00
committed by GitHub
10 changed files with 315 additions and 206 deletions

View File

@ -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
View File

@ -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",

View File

@ -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",

View File

@ -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)
}) })
}, },

View File

@ -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")
}) })
} }
} }

View File

@ -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
}) })
} }
} }

View File

@ -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()
}) })
}) })
@ -503,4 +551,4 @@ export default {
text-align: bottom; text-align: bottom;
font-size: 16px; font-size: 16px;
} }
</style> </style>

View File

@ -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
}) })
} }
} }

View File

@ -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

View File

@ -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
} }
}) })