Merge pull request #57 from 0hAodha/leaderboardFilter

Add a leaderboard filter, render optimisations and custom errors
This commit is contained in:
2023-03-19 12:44:33 +00:00
committed by GitHub
9 changed files with 191 additions and 73 deletions

View File

@ -1,3 +1,7 @@
// exports.scheduledFunction = functions.pubsub.schedule('every 10 minutes').onRun((context) => {
// functions.logger.info("Test log")
// })
// Firebase imports // Firebase imports
const functions = require("firebase-functions"); const functions = require("firebase-functions");
const admin = require('firebase-admin'); const admin = require('firebase-admin');
@ -18,13 +22,15 @@ exports.getStationData = functions.https.onRequest((request, response) => {
// fetch the "stations" collection // fetch the "stations" collection
admin.firestore().collection('stations').get().then((snapshot) => { admin.firestore().collection('stations').get().then((snapshot) => {
if (snapshot.empty) { if (snapshot.empty) {
response.status(404).send({data: "Error fetching station data from the database"}) functions.logger.log("Error fetching station data from Firestore")
response.status(404).send({data: "Error fetching station data from Firestore"})
return; return;
} }
// iterate through each of the collection's documents // iterate through each of the collection's documents
snapshot.forEach(doc => { snapshot.forEach(doc => {
jsonData.push(doc.data()); jsonData.push(doc.data());
}); });
functions.logger.log("Successfully fetched station data from Firestore")
response.json({data: jsonData}); response.json({data: jsonData});
}) })
}); });
@ -93,6 +99,7 @@ exports.postStationData = functions.https.onRequest((request, response) => {
parseString(res.data, function(err, result) { parseString(res.data, function(err, result) {
let jsonData = parseJSON(result) let jsonData = parseJSON(result)
batchWriteDB(request, response, db, jsonData, dartCodes, "Train") batchWriteDB(request, response, db, jsonData, dartCodes, "Train")
functions.logger.log("Successfully fetched and upload station data from Irish Rail")
response.send({data: "Successfully fetched and upload station data from Irish Rail"}) response.send({data: "Successfully fetched and upload station data from Irish Rail"})
}) })
}) })
@ -113,13 +120,15 @@ exports.getLiveTrainData = functions.https.onRequest((request, response) => {
// fetch the "liveTrainData" collection // fetch the "liveTrainData" collection
admin.firestore().collection('liveTrainData').get().then((snapshot) => { admin.firestore().collection('liveTrainData').get().then((snapshot) => {
if (snapshot.empty) { if (snapshot.empty) {
response.status(404).send({data: "Error fetching live train data from the database"}); functions.logger.log("Error fetching live train data from Firestore")
response.status(404).send({data: "Successfully fetched live train data from Firestore"});
return; return;
} }
// iterate through each of the collection's documents // iterate through each of the collection's documents
snapshot.forEach(doc => { snapshot.forEach(doc => {
jsonData.push(doc.data()); jsonData.push(doc.data());
}); });
functions.logger.log("Successfully fetched live train data from Firestore")
response.json({data: jsonData}); response.json({data: jsonData});
}) })
}); });
@ -187,6 +196,7 @@ exports.postLiveTrainData = functions.https.onRequest((request, response) => {
parseString(res.data, function(err, result) { parseString(res.data, function(err, result) {
let jsonData = parseJSON(result) let jsonData = parseJSON(result)
batchWriteDB(request, response, db, jsonData, "DART"); batchWriteDB(request, response, db, jsonData, "DART");
functions.logger.log("Successfully fetched and uploaded live train data from Irish Rail")
response.send({data: "Successfully fetched and uploaded live train data from Irish Rail"}); response.send({data: "Successfully fetched and uploaded live train data from Irish Rail"});
}) })
}) })
@ -203,6 +213,7 @@ exports.postLiveTrainData = functions.https.onRequest((request, response) => {
exports.getPreferences = functions.https.onCall((data, context) => { exports.getPreferences = functions.https.onCall((data, context) => {
if (!context.auth) return "Error request is not verified" if (!context.auth) return "Error request is not verified"
return admin.firestore().collection('preferences').doc(context.auth.uid).get().then((preferences) => { return admin.firestore().collection('preferences').doc(context.auth.uid).get().then((preferences) => {
functions.logger.log("Successfully fetched user preferences from Firestore")
return preferences.data() return preferences.data()
}) })
}) })
@ -211,7 +222,8 @@ exports.getPreferences = functions.https.onCall((data, context) => {
exports.postPreferences = functions.https.onCall((data, context) => { exports.postPreferences = functions.https.onCall((data, context) => {
if (!context.auth) return "Error request is not verified" if (!context.auth) return "Error request is not verified"
return admin.firestore().collection('preferences').doc(context.auth.uid).set({data}).then(() => { return admin.firestore().collection('preferences').doc(context.auth.uid).set({data}).then(() => {
return "Successfully saved preferences" functions.logger.log("Successfully saved user preferences into Firestore")
return "Successfully saved user preferences into Firestore"
}) })
}) })
@ -219,6 +231,7 @@ exports.postPreferences = functions.https.onCall((data, context) => {
exports.deletePreferences = functions.https.onCall((data, context) => { exports.deletePreferences = functions.https.onCall((data, context) => {
if (!context.auth) return "Error request is not verified" if (!context.auth) return "Error request is not verified"
return admin.firestore().collection('preferences').doc(context.auth.uid).delete().then(() => { return admin.firestore().collection('preferences').doc(context.auth.uid).delete().then(() => {
return "Successfully deleted preferences" functions.logger.log("Successfully deleted user preferences from Firestore")
return "Successfully deleted user preferences from Firestore"
}) })
}) })

View File

@ -1,12 +1,11 @@
const chai = require('chai'); const chai = require('chai');
const chaiHttp = require('chai-http'); const chaiHttp = require('chai-http');
chai.use(chaiHttp); chai.use(chaiHttp);
const expect = chai.expect; const expect = chai.expect;
describe('Firebase cloud function tests', function() { describe('Firebase cloud function tests', function() {
this.timeout(100000); this.timeout(100000);
it('Test getting live train data from the database', async() => { it('Test /getLiveTrainData', async() => {
const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net') const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net')
.get('/getLiveTrainData') .get('/getLiveTrainData')
expect(result.statusCode).to.equal(200); expect(result.statusCode).to.equal(200);
@ -22,7 +21,7 @@ describe('Firebase cloud function tests', function() {
}), }),
this.timeout(100000); this.timeout(100000);
it('Test getting station data from the database', async() => { it('Test /getStationData', async() => {
const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net') const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net')
.get('/getStationData') .get('/getStationData')
expect(result.statusCode).to.equal(200); expect(result.statusCode).to.equal(200);
@ -36,14 +35,14 @@ describe('Firebase cloud function tests', function() {
}), }),
this.timeout(100000); this.timeout(100000);
it('Test updating the database with live train data', async() => { it('Test /postLiveTrainData', async() => {
const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net') const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net')
.get('/postLiveTrainData') .get('/postLiveTrainData')
expect(result.statusCode).to.equal(200); expect(result.statusCode).to.equal(200);
}), }),
this.timeout(100000); this.timeout(100000);
it('Test updating the database with live station data', async() => { it('Test /postStationData', async() => {
const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net') const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net')
.get('/postStationData') .get('/postStationData')
expect(result.statusCode).to.equal(200); expect(result.statusCode).to.equal(200);

View File

@ -51,6 +51,7 @@ export default {
onAuthStateChanged(auth, (user) => { onAuthStateChanged(auth, (user) => {
user ? this.isLoggedIn = true : this.isLoggedIn = false user ? this.isLoggedIn = true : this.isLoggedIn = false
store.setLoginStatus(this.isLoggedIn) store.setLoginStatus(this.isLoggedIn)
store.isWaitingForLoginStatus = false
}) })
}, },

View File

@ -19,7 +19,7 @@
<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">
<h3>Delete filter preferences data</h3> <h3>Delete map filter preferences data</h3>
<button @click="deleteUserPreferences()">Delete preferences</button> <button @click="deleteUserPreferences()">Delete preferences</button>
</div> </div>
</template> </template>
@ -79,7 +79,12 @@ export default {
}) })
.catch((error) => { .catch((error) => {
this.reAuthSuccessful = false this.reAuthSuccessful = false
if (error.message.includes("wrong")) {
this.showToast("Wrong password inputted", "red")
}
else {
this.showToast(error.message, "red") this.showToast(error.message, "red")
}
}) })
}, },
@ -171,7 +176,7 @@ export default {
const deletePreferencesData = httpsCallable(functions, 'deletePreferences') const deletePreferencesData = httpsCallable(functions, 'deletePreferences')
deletePreferencesData().then(() => { deletePreferencesData().then(() => {
this.resetCredentials() this.resetCredentials()
this.showToast("Successfully deleted filter preferences", "green") this.showToast("Successfully map deleted filter preferences", "green")
}) })
.catch((error) => { .catch((error) => {
this.showToast(error.message, "red") this.showToast(error.message, "red")

View File

@ -53,15 +53,28 @@
<hr> <hr>
<h1>Leaderboard</h1> <h1>Leaderboard</h1>
<div v-for="item in orderedTrains"> <div class="form-check form-switch">
<h2>{{ this.rawData[item.jsonIndex]["TrainCode"][0] }}</h2> <input class="form-check-input" type="checkbox" role="switch" v-model="showTopEarliestLatest"/>
<p v-if="item.time > 0">{{ item.time }} mins late</p> <label class="form-check-label" for="showTopEarliestLatest">Show top three earliest and latest</label>
<p v-else>{{ item.time * -1}} mins early</p> </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> </div>
</template> </template>
<script> <script>
import {store} from '../store/store' 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 Navbar from '../components/Navbar.vue'
import BarChart from '../components/BarChart.vue' import BarChart from '../components/BarChart.vue'
import pieChart from '../components/pieChart.vue' import pieChart from '../components/pieChart.vue'
@ -69,13 +82,27 @@ export default {
name: "InsightsPage", name: "InsightsPage",
data() { data() {
const toast = () => {
createToast(this.toastMessage, {
hideProgressBar: true,
timeout: 4000,
toastBackgroundColor: this.toastBackground
})
}
return { return {
insights: {}, insights: {},
latestTrain: {}, latestTrain: {},
earliestTrain: {}, earliestTrain: {},
rawData: {}, rawData: {},
orderedTrains: [], orderedTrains: [],
store topEarliestLatest: [],
showTopEarliestLatest: false,
store,
toastMessage: "",
toastBackground: "",
toast
} }
}, },
@ -86,11 +113,25 @@ export default {
}, },
created() { created() {
if (!store.orderedTrains.length > 0) {
this.showToast("Error fetching live data", "red")
}
else {
this.insights = store.insights this.insights = store.insights
this.latestTrain = store.latestTrain this.latestTrain = store.latestTrain
this.earliestTrain = store.earliestTrain this.earliestTrain = store.earliestTrain
this.rawData = store.rawData this.rawData = store.rawData
this.orderedTrains = store.orderedTrains 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> </script>

View File

@ -10,8 +10,8 @@
<p>Password</p> <p>Password</p>
<input type="password" v-model="password" placeholder="Enter password"> <input type="password" v-model="password" placeholder="Enter password">
<input @click="login" type="submit" name="" value="Login"> <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 @click="forgotPassword = !forgotPassword; this.email = ''">Forgot password?</a>
<a><router-link to="/signup">Don't have an account?</router-link></a>
</div> </div>
<div v-else> <div v-else>
@ -70,22 +70,48 @@ export default {
login() { login() {
const auth = getAuth(app) const auth = getAuth(app)
if (!this.email || !this.password) {
this.showToast("Missing credentials", "red")
return
}
signInWithEmailAndPassword(auth, this.email, this.password).then(() => { signInWithEmailAndPassword(auth, this.email, this.password).then(() => {
this.showToast("Logged in successfully", "green") this.showToast("Logged in successfully", "green")
this.$router.push({path:'/'}) this.$router.push({path:'/'})
}) })
.catch((error) => { .catch((error) => {
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") this.showToast(error.message, "red")
}
}) })
}, },
resetPasswordEmail() { resetPasswordEmail() {
if (!this.email) {
this.showToast("Missing credentials", "red")
return
}
sendPasswordResetEmail(auth, this.email).then(() => { sendPasswordResetEmail(auth, this.email).then(() => {
this.showToast("Reset password email sent", "green") this.showToast("Reset password email sent", "green")
this.email = "" this.email = ""
}) })
.catch((error) => { .catch((error) => {
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") this.showToast(error.message, "red")
}
}) })
} }
} }

View File

@ -6,29 +6,30 @@
Map Filters Map Filters
</button> </button>
<div style="padding-bottom: 7px;" id="dropMenu" class="dropdown-menu" aria-labelledby="dropdownMenuButton1" v-on:click.stop="handleClick"> <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="container-fluid" @change="decideShowStations();">
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="showMainlandStations" v-model="showMainlandStations"/> <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>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="showDARTStations" v-model="showDARTStations"/> <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> </div>
<div id="prefHeader">TRAINS</div>
<div class="container-fluid" @change="decideShowTrains();"> <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"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="showLate" v-model="showLate"/> <input class="form-check-input" type="checkbox" role="switch" id="showLate" v-model="showLate"/>
<label class="form-check-label" for="showLate">Late Trains</label> <label class="form-check-label" for="showLate">Late Trains</label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="showOnTime" v-model="showOnTime"/> <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> <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>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="showDART" v-model="showDART"/> <input class="form-check-input" type="checkbox" role="switch" id="showDART" v-model="showDART"/>
@ -44,7 +45,7 @@
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="showNotYetRunning" v-model="showNotYetRunning"/> <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>
</div> </div>
<button id="savePref" class="btn btn-outline-info" v-if="store.loggedIn" @click="postPreferences()">Save Preferences</button> <button id="savePref" class="btn btn-outline-info" v-if="store.loggedIn" @click="postPreferences()">Save Preferences</button>
@ -66,6 +67,7 @@
<ol-source-osm /> <ol-source-osm />
</ol-tile-layer> </ol-tile-layer>
<div v-if="(!store.isWaitingForLoginStatus && !store.loggedIn) || (store.loggedIn && readyToDisplayMap)">
<!-- 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" :offset="[-14,-16]"> <ol-overlay v-if="showTrains[i]" :position="coordinate" :offset="[-14,-16]">
@ -92,10 +94,11 @@
</div> </div>
</ol-overlay> </ol-overlay>
</template> </template>
</div>
</ol-map> </ol-map>
<div> <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"> @mouseenter="isPaused = !isPaused" @mouseleave="isPaused = false">
<span v-for="message in publicMessages"> {{ message + " • " }} </span> <span v-for="message in publicMessages"> {{ message + " • " }} </span>
</MarqueeText> </MarqueeText>
@ -140,6 +143,7 @@ export default {
allStations: {}, allStations: {},
publicMessages: [], publicMessages: [],
isPaused: false, isPaused: false,
readyToDisplayMap: false,
store, store,
toastMessage: "", toastMessage: "",
@ -166,6 +170,7 @@ export default {
}, },
created() { created() {
this.readyToDisplayMap = false
let host = window.location.hostname let host = window.location.hostname
if (host === '127.0.0.1' || host === 'localhost') { if (host === '127.0.0.1' || host === 'localhost') {
this.postTrainAndStationData(); this.postTrainAndStationData();
@ -199,6 +204,7 @@ export default {
const getPreferencesData = httpsCallable(functions, 'getPreferences') const getPreferencesData = httpsCallable(functions, 'getPreferences')
getPreferencesData().then((response) => { getPreferencesData().then((response) => {
if (response.data.data) { if (response.data.data) {
this.hasPreferences = true
this.showMainlandStations = response.data.data["showMainlandStations"] this.showMainlandStations = response.data.data["showMainlandStations"]
this.showDARTStations = response.data.data["showDARTStations"] this.showDARTStations = response.data.data["showDARTStations"]
this.showLate = response.data.data["showLate"] this.showLate = response.data.data["showLate"]
@ -212,9 +218,11 @@ export default {
// update the map with the user's preferences // update the map with the user's preferences
this.decideShowStations() this.decideShowStations()
this.decideShowTrains() this.decideShowTrains()
this.readyToDisplayMap = true
} }
}) })
.catch((error) => { .catch((error) => {
this.readyToDisplayMap = true
console.log(error.message) console.log(error.message)
}) })
}, },
@ -239,9 +247,10 @@ export default {
connectFunctionsEmulator(functions, host, 5001); connectFunctionsEmulator(functions, host, 5001);
} }
this.showToast("Saving preferences", "green")
const postPreferencesData = httpsCallable(functions, 'postPreferences') const postPreferencesData = httpsCallable(functions, 'postPreferences')
postPreferencesData(preferences).then(() => { postPreferencesData(preferences).then(() => {
this.showToast("Saved preferences successfully", "green") this.readyToDisplayMap = true
}) })
.catch((error) => { .catch((error) => {
this.showToast(error.message, "red") this.showToast(error.message, "red")
@ -335,7 +344,7 @@ export default {
getTrainData().then((response) => { getTrainData().then((response) => {
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,
@ -437,10 +446,14 @@ export default {
}) })
} }
catch (error) { 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 // method to populate the database for local testing
@ -458,6 +471,9 @@ export default {
this.getTrainAndStationData() this.getTrainAndStationData()
}) })
}) })
.catch((error) => {
this.showToast(error.message, "red")
})
} }
} }
} }
@ -473,7 +489,7 @@ export default {
height: 32px; height: 32px;
} }
.trainMapIcon:hover{ .trainMapIcon:hover {
width:30px; width:30px;
height:34px; height:34px;
cursor: pointer; cursor: pointer;
@ -489,6 +505,7 @@ export default {
height: 19px; height: 19px;
cursor: pointer; cursor: pointer;
} }
#dropdownMenuButton1 { #dropdownMenuButton1 {
box-shadow: 0 0 5px 2px #6e757dbe; box-shadow: 0 0 5px 2px #6e757dbe;
} }
@ -498,15 +515,14 @@ export default {
font-size: 14.6px; font-size: 14.6px;
} }
#preferenceDropdown{ #preferenceDropdown {
position: absolute; position: absolute;
z-index: 3; z-index: 3;
right: 1%; right: 1%;
top: 11%; top: 11%;
} }
#prefHeader{ #prefHeader {
font-size: 18px; font-size: 18px;
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;
@ -529,10 +545,10 @@ export default {
font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif
} }
#savePref{ #savePref {
left:2%; left:2%;
top: 2px; top: 2px;
width: 96%; width: 95%;
position: relative; position: relative;
} }
.slideLeft-enter-active, .slideLeft-leave-active { .slideLeft-enter-active, .slideLeft-leave-active {

View File

@ -12,7 +12,6 @@
<input @click="signup" type="submit" name="" value="Sign Up"> <input @click="signup" type="submit" name="" value="Sign Up">
<a><router-link to="/login">Already have an account?</router-link></a> <a><router-link to="/login">Already have an account?</router-link></a>
</div> </div>
<p v-if="displayFirebaseError">{{ FirebaseError }}</p>
</div> </div>
</template> </template>
@ -56,14 +55,31 @@ export default {
}, },
signup() { 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) const auth = getAuth(app)
createUserWithEmailAndPassword(auth, this.email, this.password).then(() => { createUserWithEmailAndPassword(auth, this.email, this.password).then(() => {
this.showToast("Signed up successfully", "green") this.showToast("Signed up successfully", "green")
this.$router.push({path:'/'}) this.$router.push({path:'/'})
}) })
.catch((error) => { .catch((error) => {
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") this.showToast(error.message, "red")
}
}) })
} }
} }

View File

@ -11,6 +11,7 @@ export const store = reactive({
displaySelectedTrain: false, displaySelectedTrain: false,
displayedSelectedStation: false, displayedSelectedStation: false,
loggedIn: false, loggedIn: false,
isWaitingForLoginStatus: true,
setInsights(insights) { setInsights(insights) {
this.insights = insights this.insights = insights