Add a leaderboard filter, render optimisations and custom errors
This commit is contained in:
@ -51,6 +51,7 @@ export default {
|
||||
onAuthStateChanged(auth, (user) => {
|
||||
user ? this.isLoggedIn = true : this.isLoggedIn = false
|
||||
store.setLoginStatus(this.isLoggedIn)
|
||||
store.isWaitingForLoginStatus = false
|
||||
})
|
||||
},
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
<h3>Delete account</h3>
|
||||
<input @click="deleteUserAccount()" type="submit" name="" value="Delete Account">
|
||||
|
||||
<h3>Delete filter preferences data</h3>
|
||||
<h3>Delete map filter preferences data</h3>
|
||||
<button @click="deleteUserPreferences()">Delete preferences</button>
|
||||
</div>
|
||||
</template>
|
||||
@ -79,7 +79,12 @@ export default {
|
||||
})
|
||||
.catch((error) => {
|
||||
this.reAuthSuccessful = false
|
||||
this.showToast(error.message, "red")
|
||||
if (error.message.includes("wrong")) {
|
||||
this.showToast("Wrong password inputted", "red")
|
||||
}
|
||||
else {
|
||||
this.showToast(error.message, "red")
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@ -171,7 +176,7 @@ export default {
|
||||
const deletePreferencesData = httpsCallable(functions, 'deletePreferences')
|
||||
deletePreferencesData().then(() => {
|
||||
this.resetCredentials()
|
||||
this.showToast("Successfully deleted filter preferences", "green")
|
||||
this.showToast("Successfully map deleted filter preferences", "green")
|
||||
})
|
||||
.catch((error) => {
|
||||
this.showToast(error.message, "red")
|
||||
|
@ -53,15 +53,28 @@
|
||||
<hr>
|
||||
|
||||
<h1>Leaderboard</h1>
|
||||
<div v-for="item in orderedTrains">
|
||||
<h2>{{ this.rawData[item.jsonIndex]["TrainCode"][0] }}</h2>
|
||||
<p v-if="item.time > 0">{{ item.time }} mins late</p>
|
||||
<p v-else>{{ item.time * -1}} mins early</p>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" v-model="showTopEarliestLatest"/>
|
||||
<label class="form-check-label" for="showTopEarliestLatest">Show top three earliest and latest</label>
|
||||
</div>
|
||||
|
||||
<div v-if="!showTopEarliestLatest" v-for="train in orderedTrains">
|
||||
<h2>{{ this.rawData[train.jsonIndex]["TrainCode"][0] }}</h2>
|
||||
<p v-if="train.time > 0">{{ train.time }} mins late</p>
|
||||
<p v-else>{{ train.time * -1}} mins early</p>
|
||||
</div>
|
||||
|
||||
<div v-else v-for="train in topEarliestLatest">
|
||||
<h2>{{ this.rawData[train.jsonIndex]["TrainCode"][0] }}</h2>
|
||||
<p v-if="train.time > 0">{{ train.time }} mins late</p>
|
||||
<p v-else>{{ train.time * -1}} mins early</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {store} from '../store/store'
|
||||
import { createToast } from 'mosha-vue-toastify';
|
||||
import 'mosha-vue-toastify/dist/style.css'
|
||||
import Navbar from '../components/Navbar.vue'
|
||||
import BarChart from '../components/BarChart.vue'
|
||||
import pieChart from '../components/pieChart.vue'
|
||||
@ -69,13 +82,27 @@ export default {
|
||||
name: "InsightsPage",
|
||||
|
||||
data() {
|
||||
const toast = () => {
|
||||
createToast(this.toastMessage, {
|
||||
hideProgressBar: true,
|
||||
timeout: 4000,
|
||||
toastBackgroundColor: this.toastBackground
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
insights: {},
|
||||
latestTrain: {},
|
||||
earliestTrain: {},
|
||||
rawData: {},
|
||||
orderedTrains: [],
|
||||
store
|
||||
topEarliestLatest: [],
|
||||
showTopEarliestLatest: false,
|
||||
store,
|
||||
|
||||
toastMessage: "",
|
||||
toastBackground: "",
|
||||
toast
|
||||
}
|
||||
},
|
||||
|
||||
@ -86,11 +113,25 @@ export default {
|
||||
},
|
||||
|
||||
created() {
|
||||
this.insights = store.insights
|
||||
this.latestTrain = store.latestTrain
|
||||
this.earliestTrain = store.earliestTrain
|
||||
this.rawData = store.rawData
|
||||
this.orderedTrains = store.orderedTrains
|
||||
if (!store.orderedTrains.length > 0) {
|
||||
this.showToast("Error fetching live data", "red")
|
||||
}
|
||||
else {
|
||||
this.insights = store.insights
|
||||
this.latestTrain = store.latestTrain
|
||||
this.earliestTrain = store.earliestTrain
|
||||
this.rawData = store.rawData
|
||||
this.orderedTrains = store.orderedTrains
|
||||
this.topEarliestLatest = this.orderedTrains.slice(0, 3).concat(this.orderedTrains.slice(-3))
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
showToast(message, backgroundColour) {
|
||||
this.toastMessage = message
|
||||
this.toastBackground = backgroundColour
|
||||
this.toast()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -10,8 +10,8 @@
|
||||
<p>Password</p>
|
||||
<input type="password" v-model="password" placeholder="Enter password">
|
||||
<input @click="login" type="submit" name="" value="Login">
|
||||
<a><router-link to="/signup">Don't have an account?</router-link></a>
|
||||
<a @click="forgotPassword = !forgotPassword; this.email = ''">Forgot password?</a>
|
||||
<a><router-link to="/signup">Don't have an account?</router-link></a>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
@ -70,22 +70,48 @@ export default {
|
||||
|
||||
login() {
|
||||
const auth = getAuth(app)
|
||||
if (!this.email || !this.password) {
|
||||
this.showToast("Missing credentials", "red")
|
||||
return
|
||||
}
|
||||
|
||||
signInWithEmailAndPassword(auth, this.email, this.password).then(() => {
|
||||
this.showToast("Logged in successfully", "green")
|
||||
this.$router.push({path:'/'})
|
||||
})
|
||||
.catch((error) => {
|
||||
this.showToast(error.message, "red")
|
||||
if (error.message.includes("email")) {
|
||||
this.showToast("Invalid email", "red")
|
||||
}
|
||||
else if (error.message.includes("user")) {
|
||||
this.showToast("Could not find this user", "red")
|
||||
}
|
||||
else {
|
||||
this.showToast(error.message, "red")
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
resetPasswordEmail() {
|
||||
if (!this.email) {
|
||||
this.showToast("Missing credentials", "red")
|
||||
return
|
||||
}
|
||||
|
||||
sendPasswordResetEmail(auth, this.email).then(() => {
|
||||
this.showToast("Reset password email sent", "green")
|
||||
this.email = ""
|
||||
})
|
||||
.catch((error) => {
|
||||
this.showToast(error.message, "red")
|
||||
if (error.message.includes("email")) {
|
||||
this.showToast("Invalid email", "red")
|
||||
}
|
||||
else if (error.message.includes("user")) {
|
||||
this.showToast("Could not find this user", "red")
|
||||
}
|
||||
else {
|
||||
this.showToast(error.message, "red")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -6,29 +6,30 @@
|
||||
Map Filters
|
||||
</button>
|
||||
<div style="padding-bottom: 7px;" id="dropMenu" class="dropdown-menu" aria-labelledby="dropdownMenuButton1" v-on:click.stop="handleClick">
|
||||
<div id="prefHeader">~SHOW~</div>
|
||||
<div id="prefHeader">STATIONS</div>
|
||||
<div class="container-fluid" @change="decideShowStations();">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="showMainlandStations" v-model="showMainlandStations"/>
|
||||
<label class="form-check-label" for="showMainlandStations">Mainland Stations</label>
|
||||
<label class="form-check-label" for="showMainlandStations">Mainline Stations</label>
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="showDARTStations" v-model="showDARTStations"/>
|
||||
<label class="form-check-label" for="showDARTStations">Dart Stations</label>
|
||||
<label class="form-check-label" for="showDARTStations">DART Stations</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="prefHeader">TRAINS</div>
|
||||
<div class="container-fluid" @change="decideShowTrains();">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="showMainland" v-model="showMainland"/>
|
||||
<label class="form-check-label" for="showMainland">Mainline Trains</label>
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="showLate" v-model="showLate"/>
|
||||
<label class="form-check-label" for="showLate">Late Trains</label>
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="showOnTime" v-model="showOnTime"/>
|
||||
<label class="form-check-label" for="showOnTime">On-Time Trains</label>
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="showMainland" v-model="showMainland"/>
|
||||
<label class="form-check-label" for="showMainland">Mainland Trains</label>
|
||||
<label class="form-check-label" for="showOnTime">On-time Trains</label>
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="showDART" v-model="showDART"/>
|
||||
@ -44,7 +45,7 @@
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="showNotYetRunning" v-model="showNotYetRunning"/>
|
||||
<label class="form-check-label" for="showNotYetRunning">Not-Yet Running Trains</label>
|
||||
<label class="form-check-label" for="showNotYetRunning">Not-yet Running Trains</label>
|
||||
</div>
|
||||
</div>
|
||||
<button id="savePref" class="btn btn-outline-info" v-if="store.loggedIn" @click="postPreferences()">Save Preferences</button>
|
||||
@ -66,36 +67,38 @@
|
||||
<ol-source-osm />
|
||||
</ol-tile-layer>
|
||||
|
||||
<!-- train overlay -->
|
||||
<template v-for="coordinate, i in trainCoordinates" :position="inline-block">
|
||||
<ol-overlay v-if="showTrains[i]" :position="coordinate" :offset="[-14,-16]">
|
||||
<div class="overlay-content" @click="getSelectedTrain(i)">
|
||||
<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-else-if="isTrainRunning(i) && !isTrainLate(i)" src="../assets/green-train-tram-solid.png" class="trainMapIcon" alt="On-Time DART Icon">
|
||||
<img v-else src="../assets/train-tram-solid.svg" class="trainMapIcon" alt="Not Running DART Icon">
|
||||
</div>
|
||||
<div v-else>
|
||||
<img v-if="isTrainRunning(i) && isTrainLate(i)" src="../assets/red-train-solid.png" class="trainMapIcon" alt="Late Train Icon">
|
||||
<img v-else-if="isTrainRunning(i) && !isTrainLate(i)" src="../assets/green-train-solid.png" class="trainMapIcon" alt="On-Time Train Icon">
|
||||
<img v-else src="../assets/train-solid.svg" class="trainMapIcon" alt="Not Running Train Icon">
|
||||
</div>
|
||||
</div>
|
||||
</ol-overlay>
|
||||
</template>
|
||||
<div v-if="(!store.isWaitingForLoginStatus && !store.loggedIn) || (store.loggedIn && readyToDisplayMap)">
|
||||
<!-- train overlay -->
|
||||
<template v-for="coordinate, i in trainCoordinates" :position="inline-block">
|
||||
<ol-overlay v-if="showTrains[i]" :position="coordinate" :offset="[-14,-16]">
|
||||
<div class="overlay-content" @click="getSelectedTrain(i)">
|
||||
<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-else-if="isTrainRunning(i) && !isTrainLate(i)" src="../assets/green-train-tram-solid.png" class="trainMapIcon" alt="On-Time DART Icon">
|
||||
<img v-else src="../assets/train-tram-solid.svg" class="trainMapIcon" alt="Not Running DART Icon">
|
||||
</div>
|
||||
<div v-else>
|
||||
<img v-if="isTrainRunning(i) && isTrainLate(i)" src="../assets/red-train-solid.png" class="trainMapIcon" alt="Late Train Icon">
|
||||
<img v-else-if="isTrainRunning(i) && !isTrainLate(i)" src="../assets/green-train-solid.png" class="trainMapIcon" alt="On-Time Train Icon">
|
||||
<img v-else src="../assets/train-solid.svg" class="trainMapIcon" alt="Not Running Train Icon">
|
||||
</div>
|
||||
</div>
|
||||
</ol-overlay>
|
||||
</template>
|
||||
|
||||
<!-- station overlay -->
|
||||
<template v-for="coordinate, i in stationCoordinates" :position="inline-block">
|
||||
<ol-overlay v-if="showStations[i]" :position="coordinate" :offset="[-14,-16]">
|
||||
<div class="overlay-content" @click="getSelectedStation(i)">
|
||||
<img src="../assets/station.png" class="stationMapIcon" alt="Station Icon">
|
||||
</div>
|
||||
</ol-overlay>
|
||||
</template>
|
||||
<!-- station overlay -->
|
||||
<template v-for="coordinate, i in stationCoordinates" :position="inline-block">
|
||||
<ol-overlay v-if="showStations[i]" :position="coordinate" :offset="[-14,-16]">
|
||||
<div class="overlay-content" @click="getSelectedStation(i)">
|
||||
<img src="../assets/station.png" class="stationMapIcon" alt="Station Icon">
|
||||
</div>
|
||||
</ol-overlay>
|
||||
</template>
|
||||
</div>
|
||||
</ol-map>
|
||||
|
||||
<div>
|
||||
<MarqueeText v-if="publicMessages.length > 0" id="publicMessageTicker" :paused="isPaused" :duration="800" :repeat="1"
|
||||
<MarqueeText v-if="publicMessages.length>0" id="publicMessageTicker" :paused="isPaused" :duration="800" :repeat="1"
|
||||
@mouseenter="isPaused = !isPaused" @mouseleave="isPaused = false">
|
||||
<span v-for="message in publicMessages"> {{ message + " • " }} </span>
|
||||
</MarqueeText>
|
||||
@ -140,6 +143,7 @@ export default {
|
||||
allStations: {},
|
||||
publicMessages: [],
|
||||
isPaused: false,
|
||||
readyToDisplayMap: false,
|
||||
store,
|
||||
|
||||
toastMessage: "",
|
||||
@ -166,6 +170,7 @@ export default {
|
||||
},
|
||||
|
||||
created() {
|
||||
this.readyToDisplayMap = false
|
||||
let host = window.location.hostname
|
||||
if (host === '127.0.0.1' || host === 'localhost') {
|
||||
this.postTrainAndStationData();
|
||||
@ -199,6 +204,7 @@ export default {
|
||||
const getPreferencesData = httpsCallable(functions, 'getPreferences')
|
||||
getPreferencesData().then((response) => {
|
||||
if (response.data.data) {
|
||||
this.hasPreferences = true
|
||||
this.showMainlandStations = response.data.data["showMainlandStations"]
|
||||
this.showDARTStations = response.data.data["showDARTStations"]
|
||||
this.showLate = response.data.data["showLate"]
|
||||
@ -212,9 +218,11 @@ export default {
|
||||
// update the map with the user's preferences
|
||||
this.decideShowStations()
|
||||
this.decideShowTrains()
|
||||
this.readyToDisplayMap = true
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.readyToDisplayMap = true
|
||||
console.log(error.message)
|
||||
})
|
||||
},
|
||||
@ -239,9 +247,10 @@ export default {
|
||||
connectFunctionsEmulator(functions, host, 5001);
|
||||
}
|
||||
|
||||
this.showToast("Saving preferences", "green")
|
||||
const postPreferencesData = httpsCallable(functions, 'postPreferences')
|
||||
postPreferencesData(preferences).then(() => {
|
||||
this.showToast("Saved preferences successfully", "green")
|
||||
this.readyToDisplayMap = true
|
||||
})
|
||||
.catch((error) => {
|
||||
this.showToast(error.message, "red")
|
||||
@ -335,7 +344,7 @@ export default {
|
||||
|
||||
getTrainData().then((response) => {
|
||||
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 = {
|
||||
"totalNumTrains": 0,
|
||||
"numRunningTrains": 0,
|
||||
@ -437,10 +446,14 @@ export default {
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error.message)
|
||||
loader.hide();
|
||||
loader.hide()
|
||||
this.showToast(error.message, "red")
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
loader.hide()
|
||||
this.showToast("Error fetching live data", "red")
|
||||
})
|
||||
},
|
||||
|
||||
// method to populate the database for local testing
|
||||
@ -458,6 +471,9 @@ export default {
|
||||
this.getTrainAndStationData()
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
this.showToast(error.message, "red")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -473,7 +489,7 @@ export default {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.trainMapIcon:hover{
|
||||
.trainMapIcon:hover {
|
||||
width:30px;
|
||||
height:34px;
|
||||
cursor: pointer;
|
||||
@ -489,6 +505,7 @@ export default {
|
||||
height: 19px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#dropdownMenuButton1 {
|
||||
box-shadow: 0 0 5px 2px #6e757dbe;
|
||||
}
|
||||
@ -498,15 +515,14 @@ export default {
|
||||
font-size: 14.6px;
|
||||
}
|
||||
|
||||
#preferenceDropdown{
|
||||
#preferenceDropdown {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
right: 1%;
|
||||
top: 11%;
|
||||
|
||||
}
|
||||
|
||||
#prefHeader{
|
||||
#prefHeader {
|
||||
font-size: 18px;
|
||||
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
|
||||
text-align: center;
|
||||
@ -529,10 +545,10 @@ export default {
|
||||
font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif
|
||||
}
|
||||
|
||||
#savePref{
|
||||
#savePref {
|
||||
left:2%;
|
||||
top: 2px;
|
||||
width: 96%;
|
||||
width: 95%;
|
||||
position: relative;
|
||||
}
|
||||
.slideLeft-enter-active, .slideLeft-leave-active {
|
||||
|
@ -12,7 +12,6 @@
|
||||
<input @click="signup" type="submit" name="" value="Sign Up">
|
||||
<a><router-link to="/login">Already have an account?</router-link></a>
|
||||
</div>
|
||||
<p v-if="displayFirebaseError">{{ FirebaseError }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -56,14 +55,31 @@ export default {
|
||||
},
|
||||
|
||||
signup() {
|
||||
this.displayFirebaseError = false;
|
||||
if (!this.email || !this.password) {
|
||||
this.showToast("Missing credentials", "red")
|
||||
return
|
||||
}
|
||||
|
||||
if (this.password.length < 6) {
|
||||
this.showToast("Password must be 6 or more characters", "red")
|
||||
return
|
||||
}
|
||||
|
||||
const auth = getAuth(app)
|
||||
createUserWithEmailAndPassword(auth, this.email, this.password).then(() => {
|
||||
this.showToast("Signed up successfully", "green")
|
||||
this.$router.push({path:'/'})
|
||||
})
|
||||
.catch((error) => {
|
||||
this.showToast(error.message, "red")
|
||||
if (error.message.includes("already")) {
|
||||
this.showToast("Email already in use", "red")
|
||||
}
|
||||
else if (error.message.includes("email")) {
|
||||
this.showToast("Invalid email", "red")
|
||||
}
|
||||
else {
|
||||
this.showToast(error.message, "red")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ export const store = reactive({
|
||||
displaySelectedTrain: false,
|
||||
displayedSelectedStation: false,
|
||||
loggedIn: false,
|
||||
isWaitingForLoginStatus: true,
|
||||
|
||||
setInsights(insights) {
|
||||
this.insights = insights
|
||||
|
Reference in New Issue
Block a user