Merge pull request #64 from 0hAodha/myEpicNewBranch

Insights super responsive, account settings page made edible
This commit is contained in:
JLennox1
2023-03-23 13:58:41 +00:00
committed by GitHub
8 changed files with 302 additions and 424 deletions

View File

@ -1,13 +1,7 @@
<template> <template>
<div id="statsDiv">
<div id="lateGraph"> <Bar :data="chartData" :id="barChart" :options="chartOptions" />
<Bar
id="my-chart-id"
:options="chartOptions"
:data="chartData"
/>
</div>
</div>
</template> </template>
<script scoped> <script scoped>
@ -25,23 +19,38 @@ export default {
labels: ['Punctuality Percentage'], labels: ['Punctuality Percentage'],
datasets: [{ datasets: [{
label: 'Late', label: 'Late',
backgroundColor: '#FF0000', backgroundColor: 'rgba(255, 0, 0, 0.3)',
hoverBackgroundColor: 'rgba(255, 0, 0, 0.8)',
borderColor: 'rgb(255, 0, 0)',
borderWidth: 1,
data: [store.insights["percentageLate"]] data: [store.insights["percentageLate"]]
}, },
{ {
label: 'Early/ontime', label: 'Early/ontime',
backgroundColor: '#4ADC57', backgroundColor: 'rgba(74, 220, 87, 0.3)',
hoverBackgroundColor: 'rgba(74, 220, 87), 0.8)',
borderColor: 'rgb(74, 220, 87)',
borderWidth: 1,
data: [store.insights["percentageNotLate"]] data: [store.insights["percentageNotLate"]]
}] }]
}, },
chartOptions: { chartOptions: {
responsive: false responsive: true,
maintainAspectRatio: false
} }
} }
} }
} }
</script> </script>
<style scoped> <style scoped>
div{
width: 70%;
}
</style> </style>

View File

@ -1,9 +1,8 @@
<template> <template>
<div v-if="trainChart" class="piechart">
<div v-if="trainChart">
<Pie :data="trainData" :options="chartOptions" /> <Pie :data="trainData" :options="chartOptions" />
</div> </div>
<div v-if="!trainChart"> <div v-if="!trainChart" class="barchart">
<Pie :data="stationData" :options="chartOptions" /> <Pie :data="stationData" :options="chartOptions" />
</div> </div>
@ -59,7 +58,6 @@ export default {
</script> </script>
<style scoped> <style scoped>
div { div {
width: 70%; width: 70%;
} }

View File

@ -1,12 +1,11 @@
<template> <template>
<Navbar /> <Navbar />
<div id="accountDiv">
<div id="mainDiv">
<h1>Account Settings</h1> <h1>Account Settings</h1>
<p v-if="this.user">Your Email: {{ this.user.email }}</p> <p style="text-align:center" v-if="this.user">Your email: <b>{{ this.user.email }}</b><br><span id="passReset" @click="resetPasswordEmail()">Send password reset email</span></p>
<div>
<h3>Send a password reset email</h3>
<button @click="resetPasswordEmail()" type="submit" name="" value="Send Password reset email" class="button">Send Password Reset Email</button>
<h3>Enter your current password to edit account settings</h3> <h3>Enter your current password to edit the below settings</h3>
<input v-if="showCurrentPassword" type="text" v-model="currentPassword" placeholder="Enter existing password"> <input v-if="showCurrentPassword" type="text" v-model="currentPassword" placeholder="Enter existing password">
<input v-else type="password" v-model="currentPassword" placeholder="Enter existing password"> <input v-else type="password" v-model="currentPassword" placeholder="Enter existing password">
<!-- <div id="imgDiv1"> --> <!-- <div id="imgDiv1"> -->
@ -16,7 +15,7 @@
<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">
<button @click="updateUserEmail()" type="submit" name="" value="Update Email">Update email</button> <button @click="updateUserEmail()" id="emailUpdate" type="button" class="btn btn-primary" value="Update Email">Update email</button>
<h3>Change password</h3> <h3>Change password</h3>
<input v-if="showNewPassword" type="text" v-model="newPassword" placeholder="Enter new password"> <input v-if="showNewPassword" type="text" v-model="newPassword" placeholder="Enter new password">
@ -26,13 +25,13 @@
<!-- <img v-if="showPassword" id="eyeImg" src="../assets/314858_hidden_eye_icon.png" @click="this.showPassword = !this.showPassword" alt="show"> --> <!-- <img v-if="showPassword" id="eyeImg" src="../assets/314858_hidden_eye_icon.png" @click="this.showPassword = !this.showPassword" alt="show"> -->
<!-- <img v-else id = "eyeImg" src="../assets/315220_eye_icon.png" @click="this.showPassword = !this.showPassword"> --> <!-- <img v-else id = "eyeImg" src="../assets/315220_eye_icon.png" @click="this.showPassword = !this.showPassword"> -->
<!-- </div> --> <!-- </div> -->
<input @click="updateUserPassword()" type="submit" name="" value="Update Password"> <button @click="updateUserPassword()" id="passUpdate" type="button" class="btn btn-primary">Update Password</button>
<h3>Delete account</h3> <button @click="deleteUserPreferences()" id="delPref" type="button" class="btn btn-danger">Delete Map Preferences</button>
<button @click="deleteUserAccount()" type="submit" name="" value="Delete Account">Delete Account</button> <button @click="deleteUserAccount()" id="delAcc" type="button" class="btn btn-danger" value="Delete Account">Delete Account</button>
<h3>Delete map filter preferences data</h3>
<button @click="deleteUserPreferences()">Delete preferences</button> </div>
</div> </div>
</template> </template>
@ -205,49 +204,73 @@ export default {
</script> </script>
<style scoped> <style scoped>
button {
background-color: blue; h1 {
color: white; color:black;
padding: 10px 20px; text-align: center;
border-radius: 5px; }
border: none;
margin: 10px; h3 {
font-size: 16px; font-size: 18px;
padding-top: 20px;
}
#passReset {
font-size: 17px;
text-decoration: underline;
color: #39d3fa;
}
#passReset:hover {
color: #3993fa;
cursor: pointer; cursor: pointer;
} }
#accountDiv {
button:hover { position:absolute;
background-color: darkblue; right:0px;
left:0px;
bottom:0px;
background-color: rgb(255, 255, 255);
height: 100%;
display: flex;
align-items: flex-start;
justify-content: center;
} }
button:focus { #accountDiv div {
position: inherit;
padding: 15px;
background-color: rgb(255, 255, 255);
width: 45%;
height: 80%;
top: 14%;
text-align: left;
box-shadow: 0 0 4px 4px #b6b6b6;
}
#emailUpdate, #passUpdate {
position: relative;
left:10px;
width: 26%;
}
input {
border:none;
border-bottom: 1px solid #000000;
background: transparent;
outline: none; outline: none;
} }
.eye-button { #delAcc {
background-color: grey;
}
#imgDiv1{
height:8%;
left:190px;
top:260px;
position: absolute; position: absolute;
bottom: 10px;
left:10px;
} }
#imgDiv2{ #delPref {
height:8%;
left:330px;
top:400px;
position: absolute; position: absolute;
} bottom: 10px;
left:160px;
#eyeImg{
height:60%;
width:100%;
}
#eyeImg:hover{
transform: scale(1.3);
} }
</style> </style>

View File

@ -2,110 +2,82 @@
<Navbar /> <Navbar />
<!-- Table to be shown on screen widths > 1000px --> <!-- Table to be shown on screen widths > 1000px -->
<table id="statsTable" class="hideMobile"> <div class="card-group">
<tr> <div class="card">
<th colspan = "2" style="border-right: 1px solid;">Train Insights</th> <h4 style="text-align:center;">Train Insights</h4>
<th colspan = "2">Station Insights</th> <div v-if="readyToRender" class="piechart"><pieChart :id="stationPie" :trainChart="true"/></div>
</tr> <div class="card-body">
<tr> <h5 class="card-title">Train Data</h5>
<td><div v-if="readyToRender"><pieChart :id="stationPie" :trainChart="true"/></div></td> <p class="card-text">Total number of trains: {{ this.insights["totalNumTrains"] }}</p>
<td style="border-right: 1px solid;"> <ul>
<div v-if="readyToRender" id="statsDiv"> <li><p class="card-stats">Trains: {{ this.insights["numTrains"] }}</p></li>
<BarChart id="lateGraph" /> <li><p class="card-stats">Darts: {{ this.insights["numDarts"] }}</p></li>
</ul>
</div> </div>
</td> </div>
<div class="card">
<td><div style="position:relative; left:30px;" v-if="readyToRender"><pieChart :id="stationPie" :trainChart="false"/></div></td> <h4 style="text-align:center;">Station Insights</h4>
<div v-if="readyToRender" class="piechart"><pieChart :id="stationPie" :trainChart="false"/></div>
</tr> <div class="card-body">
<tr> <h5 class="card-title">Station Data</h5>
<td> <p class="card-text">Total number of stations: {{ this.insights["totalNumStations"] }}</p>
<p>Total number of trains: {{ this.insights["totalNumTrains"] }}</p>
<ul> <ul>
<li><p>Trains: {{ this.insights["numTrains"] }}</p></li> <li><p class="card-stats">Trains: {{ this.insights["numTrainStations"] }}</p></li>
<li><p>Darts: {{ this.insights["numDarts"] }}</p></li> <li><p class="card-stats">Darts: {{ this.insights["numDartStations"] }}</p></li>
</ul> </ul>
</td> </div>
<td style="border-right: 1px solid;"> </div>
<p>Number of actively running trains: {{ this.insights["numRunningTrains"] }}</p> <div class="card">
<p>Percentage late: {{ this.insights["percentageLate"] }}%</p> <h4 style="text-align:center;">Punctuality Insights</h4>
<p>Percentage early or ontime: {{ this.insights["percentageNotLate"] }}%</p> <div v-if="readyToRender"><BarChart id="barChart"/></div>
</td> <div class="card-body">
<td> <h5 class="card-title">Punctuality Data</h5>
<p>Total number of stations: {{ this.insights["totalNumStations"] }}</p> <p class="card-text">Number of actively running trains: {{ this.insights["numRunningTrains"] }}</p>
<ul> <ul>
<li><p>Trains: {{ this.insights["numTrainStations"] }}</p></li> <li><p class="card-stats">Percentage late: {{ this.insights["percentageLate"] }}%</p></li>
<li><p>Darts: {{ this.insights["numDartStations"] }}</p></li> <li><p class="card-stats">Percentage early or ontime: {{ this.insights["percentageNotLate"] }}%</p></li>
</ul> </ul>
</td> </div>
</tr> </div>
</table> </div>
<table id="statsTable" class="showMobile"> <div id="leaderboardTitleDiv"><p>Leaderboard</p></div>
<tr> <table>
<th colspan = "2" style="border-right: 1px solid;">Train Insights</th> <div style="left:3px; top:3px;" class="form-check form-switch">
<th colspan = "2">Station Insights</th>
</tr>
<tr>
<td>
<p>Total number of trains: {{ this.insights["totalNumTrains"] }}</p>
<ul>
<li><p>Trains: {{ this.insights["numTrains"] }}</p></li>
<li><p>Darts: {{ this.insights["numDarts"] }}</p></li>
</ul>
</td>
<td style="border-right: 1px solid;">
<p>Number of actively running trains: {{ this.insights["numRunningTrains"] }}</p>
<ul>
<li><p>Percentage late: {{ this.insights["percentageLate"] }}%</p></li>
<li><p>Percentage early or ontime: {{ this.insights["percentageNotLate"] }}%</p></li>
</ul>
</td>
<td>
<p>Total number of stations: {{ this.insights["totalNumStations"] }}</p>
<ul>
<li><p>Trains: {{ this.insights["numTrainStations"] }}</p></li>
<li><p>Darts: {{ this.insights["numDartStations"] }}</p></li>
</ul>
</td>
</tr>
</table>
<div id="leaderboardTitleDiv">
<p>Leaderboard</p>
<div id = "leaderboardToggle" class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" v-model="showTopEarliestLatest"/> <input class="form-check-input" type="checkbox" role="switch" v-model="showTopEarliestLatest"/>
<label v-if="showTopEarliestLatest" class="form-check-label" for="showTopEarliestLatest">Showing All Trains</label> <label class="form-check-label" for="showTopEarliestLatest">Show All Train Entries</label>
<label v-else class="form-check-label" for="showTopEarliestLatest">Showing Top & Bottom 3</label>
</div>
</div>
<div id="leaderboard">
<div v-if="!showTopEarliestLatest" v-for="train in topEarliestLatest" id="filteredLeaderboard">
<div v-if="train.time > 0" id="leaderLate">
<h2>{{ this.rawData[train.jsonIndex]["TrainCode"][0] }} - <span style="font-size:28px">Type: {{ this.rawData[train.jsonIndex]["TrainType"][0] }} | Heading {{ this.rawData[train.jsonIndex]["Direction"][0] }} </span></h2>
<p>{{ train.time }} mins late</p>
</div>
<div v-else id="leaderEarly">
<h2>{{ this.rawData[train.jsonIndex]["TrainCode"][0] }} - <span style="font-size:28px">Type: {{ this.rawData[train.jsonIndex]["TrainType"][0] }} | Heading {{ this.rawData[train.jsonIndex]["Direction"][0] }} </span></h2>
<p>{{ train.time * -1}} mins early</p>
</div>
</div>
<div v-else v-for="train in orderedTrains" id="fullLeaderBoard">
<div>
<h2>{{ this.rawData[train.jsonIndex]["TrainCode"][0] }} - <span style="font-size:28px">Type: {{ this.rawData[train.jsonIndex]["TrainType"][0] }} | Heading {{ this.rawData[train.jsonIndex]["Direction"][0] }} </span></h2>
<p v-if="train.time > 0">{{ train.time }} mins late</p>
<p v-else>{{ train.time * -1}} mins early</p>
</div>
</div>
</div> </div>
<thead>
<tr>
<th>Code</th>
<th>Time</th>
<th>Type</th>
<th>Origin</th>
<th>Destination</th>
</tr>
</thead>
<tbody v-if="!showTopEarliestLatest" v-for="train in topEarliestLatest">
<tr>
<td>{{ this.rawData[train.jsonIndex]["TrainCode"][0] }}</td>
<td v-if="train.time > 0"><span style="color: #fc1919;">{{ train.time }} mins late</span></td>
<td v-else><span style="color: rgb(129, 213, 3);">{{ train.time * -1}} mins early</span></td>
<td>{{ this.rawData[train.jsonIndex]["TrainType"][0] }}</td>
<td>{{ getOrigin(this.rawData[train.jsonIndex]["PublicMessage"][0]) }}</td>
<td>{{ getDestination(this.rawData[train.jsonIndex]["PublicMessage"][0]) }}</td>
</tr>
</tbody>
<tbody v-else v-for="train in orderedTrains">
<tr>
<td>{{ this.rawData[train.jsonIndex]["TrainCode"][0] }}</td>
<td v-if="train.time > 0"><span style="color: #fc1919;">{{ train.time }} mins late</span></td>
<td v-else><span style="color: rgb(129, 213, 3);">{{ train.time * -1}} mins early</span></td>
<td>{{ this.rawData[train.jsonIndex]["TrainType"][0] }}</td>
<td>{{ getOrigin(this.rawData[train.jsonIndex]["PublicMessage"][0]) }}</td>
<td>{{ getDestination(this.rawData[train.jsonIndex]["PublicMessage"][0]) }}</td>
</tr>
</tbody>
</table>
</template> </template>
<script> <script>
@ -186,6 +158,19 @@ export default {
this.toast() this.toast()
}, },
getOrigin(publicMessage) {
let startOrigin = publicMessage.indexOf("-") + 1
let endOrigin = publicMessage.indexOf("to ") - 1;
return publicMessage.substring(startOrigin, endOrigin);
},
getDestination(publicMessage) {
let endOrigin = publicMessage.indexOf("to ");
let startDestination = endOrigin + 3;
let endDestination = publicMessage.indexOf("(") - 1;
return publicMessage.substring(startDestination, endDestination);
},
postTrainAndStationData() { postTrainAndStationData() {
const functions = getFunctions(app); const functions = getFunctions(app);
let host = window.location.hostname let host = window.location.hostname
@ -292,109 +277,144 @@ export default {
</script> </script>
<style scoped> <style scoped>
.card-text, .card-stats {
font-size: 17px;
.showMobile{/*Hides table for screens smaller than 1000px*/
display: none;
} }
#trainPie, #stationPie{ .piechart {
width: 40%; display: flex;
position: absolute; justify-content: center;
padding-bottom: 0;
margin-bottom: 0;
height: 53%
} }
#barChart {
#lateGraph {
position:relative; position:relative;
height: 20%; padding: 10px;
width: 20%; width: 100%;
left: 10px; top: 20px;
height: 40%;
} }
th { th {
padding: 15px; padding: 15px;
text-align: center; text-align: center;
font-size: 22px; font-size: 19px;
}
#statsTable{
border: 1px solid;
width: 80%;
left: 10%;
position: relative;
}
#leaderboard{
width: 100%;
text-align: center;
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
font-size: small;
}
#leaderboardToggle{
position: relative;
top: -40px;
left: 20px;
} }
#leaderboardTitleDiv div{ /* #leaderboardToggle{
width: 10%; position: absolute;
top: -10px; top: 70px;
left:47%; left: 35%;
} } */
#leaderboardTitleDiv p { #leaderboardTitleDiv p {
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
text-align: center; text-align: center;
font-size: 50px; font-size: 50px;
padding-top:10px; padding-top:10px;
text-shadow: 2px 2px rgb(155, 155, 155);
} }
#leaderEarly{
color: rgb(129, 213, 3);
text-align: center; table {
border-spacing: 1;
border-collapse: collapse;
background: white;
border-radius: 6px;
overflow: hidden;
max-width: 1400px;
width: 100%; width: 100%;
z-index: 1; margin: 0 auto;
position: relative;
font-size: 19px;
}
*{
position: relative;
}
td,th {
padding-left: 8px;
} }
#leaderLate{ thead tr {
color: #fc1919; height: 60px;
text-align: center; background: #ffed86;
width: 100%; font-size: 16px;
z-index:2; }
tbody tr {
height: 48px;
border-bottom: 1px solid #e3f1d5;
} }
#filteredLeaderboard h2{ tbody tr:last-child {
text-shadow: 2px 1px rgb(110, 110, 110); border: 0;
border-bottom: 2px solid #d5e0f1;
} }
#fullLeaderBoard{ td, th{
text-align: center; text-align: left;
} }
@media screen and (max-width: 1000px) { td.l, th.l{
.hideMobile{ text-align: right;
display:none;
} }
.showMobile{
@media screen and (max-width: 820px){
table{
display:block; display:block;
} }
#statsTable p{ table tr,td,th, *{
font-size: 12px; display: block;
padding: 2px;
text-align: center;
} }
tr{ thead{
border: 1px solid; display:none;
} }
#statsTable{
padding: 2px; tbody tr {
border: 0px; height: auto;
padding: 8px 0;
}
tbody tr td{
padding-left: 45%;
margin-bottom: 12px;
}
tbody tr td:last-child{
margin-bottom: 0;
}
tbody tr td:before{
position: absolute;
font-weight: 700;
width: 40%;
left: 10px;
top: 0;
}
tbody tr td:nth-child(1):before {
content: "Code";
}
tbody tr td:nth-child(2):before {
content: "Time";
}
tbody tr td:nth-child(3):before {
content: "Type";
}
tbody tr td:nth-child(4):before {
content: "Origin";
}
tbody tr td:nth-child(5):before {
content: "Destination";
} }
} }
</style> </style>

View File

@ -164,7 +164,7 @@ export default {
} }
#eyeImg:hover{ #eyeImg:hover{
transform: scale(1.3); transform: scale(1.1);
} }
h1 { h1 {

View File

@ -508,8 +508,7 @@ export default {
} }
.trainMapIcon:hover { .trainMapIcon:hover {
width:30px; transform: scale(1.2);
height:34px;
cursor: pointer; cursor: pointer;
} }
@ -593,7 +592,7 @@ export default {
#publicMessageTicker { #publicMessageTicker {
z-index: 3; z-index: 3;
position: absolute; position: fixed;
bottom:0px; bottom:0px;
width:100%; width:100%;
background-color: rgb(255, 255, 125); background-color: rgb(255, 255, 125);

View File

@ -6,7 +6,7 @@
<h1>Sign Up</h1> <h1>Sign Up</h1>
<p>Email Address</p> <p>Email Address</p>
<input type="email" v-model="email" aria-describedby="emailHelp" placeholder="Enter email"> <input type="email" v-model="email" aria-describedby="emailHelp" placeholder="Enter email">
<p>Password (6 or more characters)</p> <p>Password (6+ characters)</p>
<div id="imgDiv"> <div id="imgDiv">
<img v-if="showPassword" id="eyeImg" src="../assets/314858_hidden_eye_icon.png" @click="this.showPassword = !this.showPassword" alt="show"> <img v-if="showPassword" id="eyeImg" src="../assets/314858_hidden_eye_icon.png" @click="this.showPassword = !this.showPassword" alt="show">
<img v-else id = "eyeImg" src="../assets/315220_eye_icon.png" @click="this.showPassword = !this.showPassword"> <img v-else id = "eyeImg" src="../assets/315220_eye_icon.png" @click="this.showPassword = !this.showPassword">
@ -129,7 +129,7 @@ export default {
} }
#eyeImg:hover{ #eyeImg:hover{
transform: scale(1.3); transform: scale(1.1);
} }
h1 { h1 {

View File

@ -1,171 +0,0 @@
import { reactive } from 'vue'
import { fromLonLat } from 'ol/proj.js';
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions";
import app from '../api/firebase';
export const store = reactive({
// map and insights data
insights: {},
latestTrain: {},
earliestTrain: {},
orderedTrains: [],
selectedTrain: {},
selectedStation: {},
allTrainsJSON: {},
// side bar
displaySelectedTrain: false,
displayedSelectedStation: false,
// login status
loggedIn: false,
isWaitingForLoginStatus: true,
setOrderedTrains(unorderedTrains) {
// sort in ascending order
unorderedTrains.sort((a, b) => {
return a.time - b.time
})
this.orderedTrains = unorderedTrains
},
// method to populate the database for local testing
postTrainAndStationData(host) {
const functions = getFunctions(app);
if (host === '127.0.0.1' || host === 'localhost') {
connectFunctionsEmulator(functions, host, 5001);
}
const postTrainData = httpsCallable(functions, 'postLiveTrainData');
postTrainData().then(() => {
const postStationData = httpsCallable(functions, 'postStationData');
postStationData().then(() => {
this.getTrainAndStationData(host)
})
})
.catch((error) => {
console.log(error.message)
//this.showToast(error.message, "red")
})
},
// method to fetch live train and station data from Firestore
getTrainAndStationData(host) {
const functions = getFunctions(app);
if (host === '127.0.0.1' || host == 'localhost') {
connectFunctionsEmulator(functions, host, 5001);
}
const getTrainData = httpsCallable(functions, 'getLiveTrainData');
getTrainData().then((response) => {
try {
if (!response.data) throw new Error("Error fetching live train data from the database")
var insights = {
"totalNumTrains": 0,
"numRunningTrains": 0,
"numLateRunningTrains": 0,
"numTrains": 0,
"numDarts": 0,
"totalNumStations": 0,
"numTrainStations": 0,
"numDartStations": 0
};
var unorderedTrains = [];
var currentMessages = [];
var latest = null;
var earliest = null;
var currLatestTime = null;
var currEarliestTime = null;
for (var i=0; i<response.data.length; i++) {
let train = response.data[i];
this.allTrains[i] = train;
this.trainCoordinates[i] = fromLonLat([train["TrainLongitude"][0], train["TrainLatitude"][0]])
insights["totalNumTrains"] += 1
// fill showTrains with the default value - true
this.showTrains[i] = true;
if (train["TrainType"][0] == "Train") insights["numTrains"] += 1;
else if (train["TrainType"][0] == "DART") insights["numDarts"] += 1;
// filter out \n in public messages
train["PublicMessage"][0] = train["PublicMessage"][0].replace(/\\n/g, ". ");
let publicMessage = train["PublicMessage"][0];
currentMessages.push(publicMessage);
// check if the train is running
if (train["TrainStatus"][0] == "R") {
insights["numRunningTrains"] += 1;
let startTimeStr = publicMessage.indexOf("(");
let timeEnd = publicMessage.indexOf(" ", startTimeStr+1);
let num = parseInt(publicMessage.substring(startTimeStr+1, timeEnd))
unorderedTrains.push({"time": num, "jsonIndex": i})
// check if the train is late
if (publicMessage[startTimeStr+1] != "-" && publicMessage[startTimeStr+1] != "0") {
insights["numLateRunningTrains"] += 1;
if (!latest) latest = train;
// check for a new latest train
if (num > currLatestTime) {
latest = train;
currLatestTime = num;
}
}
// train is early or ontime
else {
if (!earliest) earliest = train;
// check for a new earliest train (early trains are -x mins late)
if (num < currEarliestTime) {
earliest = train;
currEarliestTime = num;
}
}
}
}
// assign results after looping through JSON
insights["percentageLate"] = ((insights["numLateRunningTrains"] / insights["numRunningTrains"]) * 100).toFixed(2);
insights["percentageNotLate"] = (100 - insights["percentageLate"]).toFixed(2);
insights["latestTime"] = currLatestTime;
insights["earliestTime"] = currEarliestTime;
this.publicMessages = currentMessages;
// assign the results to the Vue Store
store.setEarliestTrain(earliest);
store.setLatestTrain(latest);
store.setRawData(response.data);
store.setOrderedTrains(unorderedTrains);
const getStationData = httpsCallable(functions, 'getStationData');
getStationData().then((response) => {
if (!response.data) throw new Error("Error fetching station from the database");
for (var i=0; i<response.data.length; i++) {
let station = response.data[i];
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
this.showStations[i] = true;
if (station["StationType"][0] == "DART") insights["numDartStations"] += 1;
else if (station["StationType"][0] == "Train") insights["numTrainStations"] += 1;
store.setInsights(insights);
loader.hide();
// request the user's preferences
this.getPreferences()
}
})
}
catch (error) {
//loader.hide()
//this.showToast(error.message, "red")
}
})
.catch((error) => {
//loader.hide()
//this.showToast("Error fetching live data", "red")
})
}
})