Merge pull request #31 from 0hAodha/userAuth

Implement user auth with Firebase
This commit is contained in:
2023-03-07 18:21:45 +00:00
committed by GitHub
28 changed files with 1470 additions and 1294 deletions

1
dist/assets/InsightsPage-4addc08f.js vendored Normal file
View File

@ -0,0 +1 @@
import{s as n,n as u}from"./navbar-764b96b5.js";import{_,r as p,o as e,c as a,a as g,b as s,t,d as o,F as l,e as m,p as T,f as b}from"./index-c8c418b0.js";const f={name:"InsightsPage",data(){return{insights:{},latestTrain:{},earliestTrain:{},rawData:{},orderedTrains:[],store:n}},components:{navbar:u},created(){this.insights=n.insights,this.latestTrain=n.latestTrain,this.earliestTrain=n.earliestTrain,this.rawData=n.rawData,this.orderedTrains=n.orderedTrains}},h=i=>(T("data-v-1daafc6b"),i=i(),b(),i),y=h(()=>s("h1",null,"Insights",-1)),v={key:0},I={key:0},k={key:1},C=h(()=>s("h1",null,"Leaderboard",-1)),D={key:0},N={key:1};function S(i,w,x,L,d,P){const c=p("navbar");return e(),a(l,null,[g(c),y,this.insights?(e(),a("div",v,[s("p",null,"Total number of trains: "+t(this.insights.totalNumTrains),1),s("p",null,"Number of actively running trains: "+t(this.insights.numRunningTrains),1),s("p",null,"Percentage late: "+t(this.insights.percentageLate)+"%",1),s("p",null,"Percentage early or ontime: "+t(this.insights.percentageNotLate)+"%",1),this.latestTrain.TrainCode?(e(),a("p",I,"Latest train: "+t(this.latestTrain.TrainCode[0])+", "+t(this.insights.latestTime)+" mins late",1)):o("",!0),this.earliestTrain.TrainCode?(e(),a("p",k,"Earliest train: "+t(this.earliestTrain.TrainCode[0])+", "+t(this.insights.earliestTime*-1)+" mins early",1)):o("",!0),s("p",null,"Mainland: "+t(this.insights.numMainland),1),s("p",null,"Suburban: "+t(this.insights.numSuburban),1),s("p",null,"Darts: "+t(this.insights.numDart),1)])):o("",!0),C,(e(!0),a(l,null,m(d.orderedTrains,r=>(e(),a("div",null,[s("h2",null,t(this.rawData[r.jsonIndex].TrainCode[0]),1),r.time>0?(e(),a("p",D,t(r.time)+" mins late",1)):(e(),a("p",N,t(r.time*-1)+" mins early",1))]))),256))],64)}const $=_(f,[["render",S],["__scopeId","data-v-1daafc6b"]]);export{$ as default};

1
dist/assets/InsightsPage-d4adcdf9.css vendored Normal file
View File

@ -0,0 +1 @@
.navbarLink[data-v-1daafc6b]{font-family:Franklin Gothic Medium,Arial Narrow,Arial,sans-serif;font-size:24px}body[data-v-1daafc6b]{background-color:#2c6666}

421
dist/assets/MapPage-12ef7403.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/assets/MapPage-56e92111.css vendored Normal file
View File

@ -0,0 +1 @@
.overlay-content[data-v-0c5ec56d]{width:1%}.trainMapIcon[data-v-0c5ec56d]{width:28px;height:32px}.slideLeft-enter-active[data-v-0c5ec56d],.slideLeft-leave-active[data-v-0c5ec56d]{transition:opacity .5s;transition:all .8s}.slideLeft-enter-from[data-v-0c5ec56d],.slideLeft-leave-to[data-v-0c5ec56d]{opacity:0;transform:translate(-100px)}@keyframes gradient-0c5ec56d{0%{background-position:0% 50%}50%{background-position:100% 50%}to{background-position:0% 50%}}#sidebar[data-v-0c5ec56d]{position:absolute;height:85%;width:20%;left:2%;top:12%;z-index:2;text-align:center;animation:gradient-0c5ec56d 15s ease infinite;background:linear-gradient(45deg,#000000,#111111,#222222,#333333,#444444,#555555);background-size:400%,400%;box-shadow:0 0 4px 2px #333;overflow:hidden;font-family:Franklin Gothic Medium,Arial Narrow,Arial,sans-serif}#sidebarHeader[data-v-0c5ec56d]{position:relative;top:0%;height:15%;width:100%;overflow:hidden}#sidebarDiv[data-v-0c5ec56d]{position:absolute;height:80%;width:100%;color:#fff}#headerImage[data-v-0c5ec56d]{height:80%;width:auto;overflow:hidden;position:relative;top:10px}#xButton[data-v-0c5ec56d]{font-size:80%;font-family:Georgia;color:#fff;position:absolute;top:10px;right:10px}#xButton[data-v-0c5ec56d]:hover{color:red}#hoverButton[data-v-0c5ec56d]{z-index:3;position:absolute;bottom:0px;width:100%}

10
dist/assets/index-a5eb0783.css vendored Normal file

File diff suppressed because one or more lines are too long

575
dist/assets/index-c8c418b0.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
dist/assets/loginpage-acff9941.js vendored Normal file
View File

@ -0,0 +1 @@
import{_ as c,r,o as i,c as l,b as e,k as p,a as _,w as d,h as u,p as h,f}from"./index-c8c418b0.js";const m={name:"loginpage",methods:{submit(){this.$router.push("/")}}},t=o=>(h("data-v-9ffc39fa"),o=o(),f(),o),g={id:"background"},v={class:"loginbox"},x=t(()=>e("img",{src:"https://cdn.discordapp.com/attachments/1017419092447207436/1063092138029625394/pixil-frame-0.png",class:"avatar"},null,-1)),w=t(()=>e("h1",null,"Login Here",-1)),b=t(()=>e("p",null,"Username",-1)),k=t(()=>e("input",{type:"text",name:"",placeholder:"Enter Username"},null,-1)),y=t(()=>e("p",null,"Password",-1)),$=t(()=>e("input",{type:"password",name:"",placeholder:"Password"},null,-1)),I=t(()=>e("a",{href:"#"},"Lost your password?",-1)),B=t(()=>e("br",null,null,-1));function C(o,s,L,N,S,n){const a=r("router-link");return i(),l("div",g,[e("div",v,[x,w,e("form",null,[b,k,y,$,e("input",{type:"submit",name:"",value:"Login",onClick:s[0]||(s[0]=p(V=>n.submit(),["stop","prevent"]))}),I,B,e("a",null,[_(a,{to:"/signup"},{default:d(()=>[u("Don't have an account?")]),_:1})])])])])}const P=c(m,[["render",C],["__scopeId","data-v-9ffc39fa"]]);export{P as default};

1
dist/assets/loginpage-caea8f93.css vendored Normal file
View File

@ -0,0 +1 @@
#background[data-v-9ffc39fa]{margin:0;padding:0;width:100%;height:100%;position:absolute;background-color:#e0e0e0;font-family:sans-serif}.loginbox[data-v-9ffc39fa]{height:420px;width:320px;background:#000;color:#fff;top:50%;left:50%;position:absolute;transform:translate(-50%,-50%);box-sizing:border-box;padding:70px 30px}h1[data-v-9ffc39fa]{margin:0;padding:0 0 20px;font-size:22px;text-align:center}.loginbox p[data-v-9ffc39fa]{margin:0;padding:0;font-weight:700}.loginbox input[data-v-9ffc39fa]{width:100%;margin-bottom:20px}.loginbox input[type=text][data-v-9ffc39fa],input[type=password][data-v-9ffc39fa]{border:none;border-bottom:1px solid #fff;background:transparent;outline:none;height:40px;color:#fff;font-size:16px}.loginbox input[type=submit][data-v-9ffc39fa]:hover{cursor:pointer;background:#66a3ff;color:#000}.loginbox a[data-v-9ffc39fa]{text-decoration:none;font-size:12px;line-height:20px;color:#a9a9a9}.loginbox a[data-v-9ffc39fa]:hover{color:#ffc107}.loginbox input[type=submit][data-v-9ffc39fa]{border:none;outline:none;height:40px;background:#0052cc;font-size:18px;border-radius:20px}.avatar[data-v-9ffc39fa]{width:100px;height:100px;border-radius:50%;position:absolute;top:-50px;left:calc(50% - 50px)}

1
dist/assets/navbar-764b96b5.js vendored Normal file
View File

@ -0,0 +1 @@
import{g as _,_ as d,r as l,o as h,c as p,b as a,a as e,w as n,h as i,p as v,f as g}from"./index-c8c418b0.js";const N=_({insights:{},latestTrain:{},earliestTrain:{},orderedTrains:[],rawData:{},setInsights(t){this.insights=t},setLatestTrain(t){this.latestTrain=t},setEarliestTrain(t){this.earliestTrain=t},setRawData(t){this.rawData=t},setOrderedTrains(t){t.sort((o,r)=>o.time-r.time),this.orderedTrains=t}});const m={name:"navbar"},c=t=>(v("data-v-8a119f70"),t=t(),g(),t),f={class:"navbar navbar-light bg-light"},u={class:"container-fluid"},b=c(()=>a("img",{src:"https://cdn.discordapp.com/attachments/1017419092447207436/1063092138029625394/pixil-frame-0.png",alt:"mascot",width:"55",height:"40",class:"d-inline-block align-text-middle"},null,-1)),T=c(()=>a("b",null,"Irish Rail Tracker",-1)),k={class:"navbarLink"},x={class:"navbarLink"},w={class:"navbarLink"};function I(t,o,r,L,$,B){const s=l("router-link");return h(),p("nav",f,[a("div",u,[e(s,{to:"/",class:"navbar-brand"},{default:n(()=>[b,T]),_:1}),a("a",k,[e(s,{to:"/"},{default:n(()=>[i("Home")]),_:1})]),a("a",x,[e(s,{to:"/insights"},{default:n(()=>[i("Insights")]),_:1})]),a("a",w,[e(s,{to:"/login"},{default:n(()=>[i("Login")]),_:1})])])])}const S=d(m,[["render",I],["__scopeId","data-v-8a119f70"]]);export{S as n,N as s};

1
dist/assets/navbar-df4836e9.css vendored Normal file
View File

@ -0,0 +1 @@
.navbarLink[data-v-8a119f70]{font-family:Franklin Gothic Medium,Arial Narrow,Arial,sans-serif;font-size:150%}

1
dist/assets/signup-c9878365.js vendored Normal file
View File

@ -0,0 +1 @@
import{_ as p,r,o as c,c as i,b as e,k as _,a as d,w as l,h as u,p as h,f as m}from"./index-c8c418b0.js";const f={name:"signuppage",methods:{submit(){this.$router.push("/")}}},t=s=>(h("data-v-1069659b"),s=s(),m(),s),g={id:"background"},v={class:"loginbox"},b=t(()=>e("img",{src:"https://cdn.discordapp.com/attachments/1017419092447207436/1063092138029625394/pixil-frame-0.png",class:"avatar"},null,-1)),x=t(()=>e("h1",null,"Sign Up Here",-1)),w=t(()=>e("p",null,"Username",-1)),k=t(()=>e("input",{type:"text",name:"",placeholder:"Enter Username"},null,-1)),y=t(()=>e("p",null,"Password",-1)),S=t(()=>e("input",{type:"password",name:"",placeholder:"Password"},null,-1)),$=t(()=>e("a",{href:"#"},"Lost your password?",-1)),I=t(()=>e("br",null,null,-1));function U(s,o,B,C,N,n){const a=r("router-link");return c(),i("div",g,[e("div",v,[b,x,e("form",null,[w,k,y,S,e("input",{type:"submit",name:"",value:"Sign Up",onClick:o[0]||(o[0]=_(V=>n.submit(),["stop","prevent"]))}),$,I,e("a",null,[d(a,{to:"/login"},{default:l(()=>[u("Already have an account?")]),_:1})])])])])}const P=p(f,[["render",U],["__scopeId","data-v-1069659b"]]);export{P as default};

1
dist/assets/signup-ceddb310.css vendored Normal file
View File

@ -0,0 +1 @@
#background[data-v-1069659b]{margin:0;padding:0;width:100%;height:100%;position:absolute;background-color:#e0e0e0;font-family:sans-serif}.loginbox[data-v-1069659b]{height:420px;width:320px;background:#000;color:#fff;top:50%;left:50%;position:absolute;transform:translate(-50%,-50%);box-sizing:border-box;padding:70px 30px}h1[data-v-1069659b]{margin:0;padding:0 0 20px;font-size:22px;text-align:center}.loginbox p[data-v-1069659b]{margin:0;padding:0;font-weight:700}.loginbox input[data-v-1069659b]{width:100%;margin-bottom:20px}.loginbox input[type=text][data-v-1069659b],input[type=password][data-v-1069659b]{border:none;border-bottom:1px solid #fff;background:transparent;outline:none;height:40px;color:#fff;font-size:16px}.loginbox input[type=submit][data-v-1069659b]:hover{cursor:pointer;background:#00df00;color:#000}.loginbox a[data-v-1069659b]{text-decoration:none;font-size:12px;line-height:20px;color:#a9a9a9}.loginbox a[data-v-1069659b]:hover{color:#ffc107}.loginbox input[type=submit][data-v-1069659b]{border:none;outline:none;height:40px;background:#00a800;font-size:18px;border-radius:20px}.avatar[data-v-1069659b]{width:100px;height:100px;border-radius:50%;position:absolute;top:-50px;left:calc(50% - 50px)}

4
dist/index.html vendored
View File

@ -5,8 +5,8 @@
<link rel="icon" href="/assets/train-solid-e7249eb7.svg">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Irish Rail Tracker</title>
<script type="module" crossorigin src="/assets/index-ed2bec8f.js"></script>
<link rel="stylesheet" href="/assets/index-debbf736.css">
<script type="module" crossorigin src="/assets/index-c8c418b0.js"></script>
<link rel="stylesheet" href="/assets/index-a5eb0783.css">
</head>
<body>
<div id="app"></div>

View File

@ -165,4 +165,15 @@ exports.postLiveTrainData = functions.https.onRequest((request, response) => {
})
})
})
})
exports.securefunction = functions.https.onCall((data, context) => {
if (typeof context.auth === undefined) {
// user not logged in
return "User is not logged in"
}
else {
// user logged in
return "User is logged in"
}
})

11
package-lock.json generated
View File

@ -15,6 +15,7 @@
"ol": "^7.2.2",
"vue": "^3.2.45",
"vue-loading-overlay": "^6.0.3",
"vue-marquee-text-component": "^2.0.1",
"vue-router": "^4.1.6",
"vue3-openlayers": "^0.1.71"
},
@ -1341,7 +1342,6 @@
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.2.tgz",
"integrity": "sha512-9ashVQskuh5AZEZ1JdQWp1GqSoC1e1G87MzRqg2gIfVAQ7Qn9K+uFj8EcniUFA4P2NLZfV+TOlX1SzoKfo+s7w==",
"hasInstallScript": true,
"optional": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
@ -2236,6 +2236,15 @@
"vue": "^3.2.0"
}
},
"node_modules/vue-marquee-text-component": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/vue-marquee-text-component/-/vue-marquee-text-component-2.0.1.tgz",
"integrity": "sha512-dbeRwDY5neOJcWZrDFU2tJMhPSsxN25ZpNYeZdt0jkseg1MbyGKzrfEH9nrCFZRkEfqhxG+ukyzwVwR9US5sTQ==",
"dependencies": {
"core-js": "^3.18.0",
"vue": "^3.2.19"
}
},
"node_modules/vue-router": {
"version": "4.1.6",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz",

View File

@ -15,6 +15,7 @@
"ol": "^7.2.2",
"vue": "^3.2.45",
"vue-loading-overlay": "^6.0.3",
"vue-marquee-text-component": "^2.0.1",
"vue-router": "^4.1.6",
"vue3-openlayers": "^0.1.71"
},

56
src/components/Navbar.vue Normal file
View File

@ -0,0 +1,56 @@
<template>
<nav class="navbar navbar-light bg-light">
<div class="container-fluid">
<router-link to="/" class="navbar-brand">
<img src="https://cdn.discordapp.com/attachments/1017419092447207436/1063092138029625394/pixil-frame-0.png" alt="mascot" width="55" height="40" class="d-inline-block align-text-middle">
<b>Irish Rail Tracker</b>
</router-link>
<a class="navbarLink"><router-link to="/">Home</router-link></a>
<a class="navbarLink"><router-link to="/insights">Insights</router-link></a>
<a v-if="isLoggedIn" class="navbarLink"><router-link to="/secure">Secure</router-link></a>
<a v-if="isLoggedIn" class="navbarLink"><router-link @click="logout" to="/">Logout</router-link></a>
<a v-if="!isLoggedIn" class="navbarLink"><router-link to="/login">Login</router-link></a>
<a v-if="!isLoggedIn" class="navbarLink"><router-link to="/signup">Sign Up</router-link></a>
</div>
</nav>
</template>
<script>
import app from "../api/firebase"
import {getAuth, onAuthStateChanged, signOut} from "firebase/auth"
export default {
name: "Navbar",
data() {
return {
isLoggedIn: false
}
},
created() {
// check if user is logged in
const auth = getAuth(app);
onAuthStateChanged(auth, (user) => {
user ? this.isLoggedIn = true : this.isLoggedIn = false
})
},
methods: {
logout() {
signOut(getAuth(app)).then(() => {
// send user back to home page
this.$router.push("/")
})
}
}
}
</script>
<style scoped>
.navbarLink{
font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
font-size: 150%;
}
</style>

View File

@ -1,30 +0,0 @@
<template>
<nav class="navbar navbar-light bg-light">
<div class="container-fluid">
<router-link to ="/" class="navbar-brand">
<img src="https://cdn.discordapp.com/attachments/1017419092447207436/1063092138029625394/pixil-frame-0.png" alt="mascot" width="55" height="40" class="d-inline-block align-text-middle">
<b>Irish Rail Tracker</b>
</router-link>
<a class = "navbarLink"><router-link to="/">Home</router-link></a>
<a class = "navbarLink"><router-link to="/insights">Insights</router-link></a>
<a class = "navbarLink"><router-link to="/login">Login</router-link></a>
</div>
</nav>
</template>
<script>
export default {
name: "navbar"
}
</script>
<style scoped>
.navbarLink{
font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
font-size: 150%;
}
</style>

View File

@ -1,6 +1,5 @@
<template>
<navbar></navbar>
<Navbar />
<h1>Insights</h1>
<div v-if="this.insights">
@ -27,7 +26,7 @@
<script>
import {store} from '../store/store'
import navbar from '../components/navbar.vue'
import Navbar from '../components/Navbar.vue'
export default {
name: "InsightsPage",
@ -43,8 +42,7 @@ export default {
},
components: {
// SidebarPanel
navbar
Navbar
},
created() {
@ -58,14 +56,7 @@ export default {
</script>
<style scoped>
.navbarLink{
font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
font-size: 24px;
}
body{
background-color: rgb(44, 102, 102);
}
</style>

144
src/pages/LoginPage.vue Normal file
View File

@ -0,0 +1,144 @@
<template>
<Navbar />
<div id="background">
<div class="loginbox">
<img src="https://cdn.discordapp.com/attachments/1017419092447207436/1063092138029625394/pixil-frame-0.png" class="avatar">
<h1>Login</h1>
<p>Email Address</p>
<input type="email" v-model="email" aria-describedby="emailHelp" placeholder="Enter email">
<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>
</div>
</div>
</template>
<script>
import app from '../api/firebase';
import {getAuth, signInWithEmailAndPassword} from "firebase/auth"
import Navbar from '../components/Navbar.vue'
export default {
name: "LoginPage",
data() {
return {
email: "",
password: ""
}
},
components: {
Navbar
},
methods: {
login() {
const auth = getAuth(app)
signInWithEmailAndPassword(auth, this.email, this.password)
.then((userCredential) => {
const user = userCredential.user
this.$router.push({path:'/secure'})
})
.catch((error) => {
const errorCode = error.code
const errorMessage = error.message
console.log(errorCode)
console.log(errorMessage)
})
}
}
}
</script>
<style scoped>
#background {
margin: 0;
padding: 0;
width:100%;
height: 100%;
position: absolute;
background-color: #e0e0e0;
font-family: sans-serif;
}
.loginbox {
height: 420px;
width: 320px;
background: #000;
color: #fff;
top: 50%;
left:50%;
position: absolute;
transform: translate(-50%,-50%);
box-sizing: border-box;
padding: 70px 30px;
}
h1 {
margin: 0;
padding: 0 0 20px;
font-size: 22px;
text-align:center;
}
.loginbox p {
margin: 0;
padding:0;
font-weight: bold;
}
.loginbox input {
width:100%;
margin-bottom: 20px;
}
.loginbox input[type="email"], input[type="password"] {
border: none;
border-bottom: 1px solid #fff;
background: transparent;
outline: none;
height: 40px;
color: #fff;
font-size: 16px;
}
.loginbox input[type="submit"]:hover {
cursor: pointer;
background: #66a3ff;
color: #000;
}
.loginbox a {
text-decoration: none;
font-size: 12px;
line-height: 20px;
color: darkgray;
}
.loginbox a:hover {
color: #ffc107;
}
.loginbox input[type="submit"] {
border: none;
outline: none;
height:40px;
background: #0052cc;
font-size: 18px;
border-radius:20px;
}
.avatar {
width: 100px;
height: 100px;
border-radius: 50%;
position: absolute;
top:-50px;
left: calc(50% - 50px);
}
</style>

View File

@ -1,10 +1,6 @@
<template>
<navbar></navbar>
<button id="hoverButton" @click="postLiveTrainData">Populate Database</button>
<div><SidebarPanel /></div>
<Navbar />
<!-- <button id="hoverButton" @click="postLiveTrainData">Populate Database</button> -->
<!--Sidebar, fades out on click of X button-->
<transition id="sidebar" name="slideLeft">
@ -41,6 +37,13 @@
</ol-overlay>
</template>
</ol-map>
<div>
<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>
</div>
</template>
<script>
@ -49,9 +52,8 @@ import { ref } from 'vue';
import {fromLonLat, toLonLat} from 'ol/proj.js';
import app from '../api/firebase';
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions";
// import SidebarPanel from '../components/SidebarPanel.vue'
import navbar from '../components/navbar.vue'
import { set } from 'ol/transform';
import Navbar from '../components/Navbar.vue'
import MarqueeText from 'vue-marquee-text-component'
export default {
name: "MapPage",
@ -81,13 +83,16 @@ export default {
allDataMap: {},
selectedDataMap: {},
display: false,
store
}
store,
publicMessages: [],
isPaused: false,
}
},
components: {
// SidebarPanel
navbar
Navbar,
MarqueeText
},
created() {
@ -154,6 +159,8 @@ export default {
var currLatestTime = null
var currEarliestTime = null
var currentMessages = []
// create an array of coordinates and hashmap with the key-values {index: JSON obj}
for (var i=0; i<this.dbLiveTrainData.length; i++) {
let train = this.dbLiveTrainData[i];
@ -164,10 +171,12 @@ export default {
else if (train["TrainType"][0] == "S") insights["numSuburban"] += 1;
else if (train["TrainType"][0] == "D") insights["numDart"] += 1;
let publicMessage = train["PublicMessage"][0];
currentMessages.push(publicMessage)
// check if the train is running
if (this.dbLiveTrainData[i]["TrainStatus"][0] == "R") {
insights["numRunningTrains"] += 1;
let publicMessage = train["PublicMessage"][0];
let startTimeStr = publicMessage.indexOf("(");
let timeEnd = publicMessage.indexOf(" ", startTimeStr+1);
let num = parseInt(publicMessage.substring(startTimeStr+1, timeEnd))
@ -203,6 +212,7 @@ export default {
insights["totalNumTrains"] = Object.keys(this.allDataMap).length;
insights["latestTime"] = currLatestTime;
insights["earliestTime"] = currEarliestTime
this.publicMessages = currentMessages
// assign the results to the Vue Store
store.setInsights(insights);
@ -319,12 +329,15 @@ export default {
color:red;
}
#hoverButton{
#publicMessageTicker {
z-index: 3;
position: absolute;
bottom:0px;
width:100%;
background-color: rgb(255, 255, 125);
color: black;
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
text-align: bottom;
font-size: 17px;
}
</style>

32
src/pages/SecurePage.vue Normal file
View File

@ -0,0 +1,32 @@
<template>
<Navbar />
<h1>Secure</h1>
</template>
<script>
import Navbar from '../components/Navbar.vue'
import app from '../api/firebase'
import {getFunctions, httpsCallable, connectFunctionsEmulator} from "firebase/functions"
export default {
name: "SecurePage",
components: {
Navbar,
},
created() {
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);
})
}
}
</script>
<style scoped>
</style>

144
src/pages/SignUpPage.vue Normal file
View File

@ -0,0 +1,144 @@
<template>
<Navbar />
<div id="background">
<div class="loginbox">
<img src="https://cdn.discordapp.com/attachments/1017419092447207436/1063092138029625394/pixil-frame-0.png" class="avatar">
<h1>Sign Up</h1>
<p>Email Address</p>
<input type="email" v-model="email" aria-describedby="emailHelp" placeholder="Enter email">
<p>Password</p>
<input type="password" v-model="password" placeholder="Enter password">
<input @click="signup" type="submit" name="" value="Sign Up">
<a><router-link to="/login">Already have an account?</router-link></a>
</div>
</div>
</template>
<script>
import app from '../api/firebase';
import {getAuth, createUserWithEmailAndPassword} from "firebase/auth"
import Navbar from '../components/Navbar.vue'
export default {
name: "SignupPage",
data() {
return {
email: "",
password: ""
}
},
components: {
Navbar
},
methods: {
signup() {
const auth = getAuth(app)
createUserWithEmailAndPassword(auth, this.email, this.password)
.then((userCredential) => {
const user = userCredential.user
this.$router.push({path:'/secure'})
})
.catch((error) => {
const errorCode = error.code
const errorMessage = error.message
console.log(errorCode)
console.log(errorMessage)
})
}
}
}
</script>
<style scoped>
#background {
margin: 0;
padding: 0;
width:100%;
height: 100%;
position: absolute;
background-color: #e0e0e0;
font-family: sans-serif;
}
.loginbox {
height: 420px;
width: 320px;
background: #000;
color: #fff;
top: 50%;
left:50%;
position: absolute;
transform: translate(-50%,-50%);
box-sizing: border-box;
padding: 70px 30px;
}
h1 {
margin: 0;
padding: 0 0 20px;
font-size: 22px;
text-align:center;
}
.loginbox p {
margin: 0;
padding:0;
font-weight: bold;
}
.loginbox input {
width:100%;
margin-bottom: 20px;
}
.loginbox input[type="email"], input[type="password"] {
border: none;
border-bottom: 1px solid #fff;
background: transparent;
outline: none;
height: 40px;
color: #fff;
font-size: 16px;
}
.loginbox input[type="submit"]:hover {
cursor: pointer;
background: #66a3ff;
color: #000;
}
.loginbox a {
text-decoration: none;
font-size: 12px;
line-height: 20px;
color: darkgray;
}
.loginbox a:hover {
color: #ffc107;
}
.loginbox input[type="submit"] {
border: none;
outline: none;
height:40px;
background: #0052cc;
font-size: 18px;
border-radius:20px;
}
.avatar {
width: 100px;
height: 100px;
border-radius: 50%;
position: absolute;
top:-50px;
left: calc(50% - 50px);
}
</style>

View File

@ -1,119 +0,0 @@
<template>
<div id = "background">
<div class = "loginbox">
<img src="https://cdn.discordapp.com/attachments/1017419092447207436/1063092138029625394/pixil-frame-0.png" class="avatar">
<h1>Login Here</h1>
<form>
<p>Username</p>
<input type="text" name="" placeholder="Enter Username">
<p>Password</p>
<input type="password" name="" placeholder="Password">
<input type="submit" name="" value="Login" @click.stop.prevent="submit()">
<a href="#">Lost your password?</a><br>
<a><router-link to="/signup">Don't have an account?</router-link></a>
</form>
</div>
</div>
</template>
<script>
export default {
name: "loginpage",
methods: {
submit(){
//if you want to send any data into server before redirection then you can do it here
this.$router.push("/");
}
}
}
</script>
<style scoped>
#background{
margin: 0;
padding: 0;
width:100%;
height: 100%;
position: absolute;
background-color: #e0e0e0;
font-family: sans-serif;
}
.loginbox{
height: 420px;
width: 320px;
background: #000;
color: #fff;
top: 50%;
left:50%;
position: absolute;
transform: translate(-50%,-50%);
box-sizing: border-box;
padding: 70px 30px;
}
h1{
margin: 0;
padding: 0 0 20px;
font-size: 22px;
text-align:center;
}
.loginbox p{
margin: 0;
padding:0;
font-weight: bold;
}
.loginbox input{
width:100%;
margin-bottom: 20px;
}
.loginbox input[type="text"], input[type="password"]{
border: none;
border-bottom: 1px solid #fff;
background: transparent;
outline: none;
height: 40px;
color: #fff;
font-size: 16px;
}
.loginbox input[type="submit"]:hover{
cursor: pointer;
background: #66a3ff;
color: #000;
}
.loginbox a{
text-decoration: none;
font-size: 12px;
line-height: 20px;
color: darkgray;
}
.loginbox a:hover{
color: #ffc107;
}
.loginbox input[type="submit"]
{
border: none;
outline: none;
height:40px;
background: #0052cc;
font-size: 18px;
border-radius:20px;
}
.avatar{
width: 100px;
height: 100px;
border-radius: 50%;
position: absolute;
top:-50px;
left: calc(50% - 50px);
}
</style>

View File

@ -1,119 +0,0 @@
<template>
<div id = "background">
<div class = "loginbox">
<img src="https://cdn.discordapp.com/attachments/1017419092447207436/1063092138029625394/pixil-frame-0.png" class="avatar">
<h1>Sign Up Here</h1>
<form>
<p>Username</p>
<input type="text" name="" placeholder="Enter Username">
<p>Password</p>
<input type="password" name="" placeholder="Password">
<input type="submit" name="" value="Sign Up" @click.stop.prevent="submit()">
<a href="#">Lost your password?</a><br>
<a><router-link to="/login">Already have an account?</router-link></a>
</form>
</div>
</div>
</template>
<script>
export default {
name: "signuppage",
methods: {
submit(){
//if you want to send any data into server before redirection then you can do it here
this.$router.push("/");
}
}
}
</script>
<style scoped>
#background{
margin: 0;
padding: 0;
width:100%;
height: 100%;
position: absolute;
background-color: #e0e0e0;
font-family: sans-serif;
}
.loginbox{
height: 420px;
width: 320px;
background: #000;
color: #fff;
top: 50%;
left:50%;
position: absolute;
transform: translate(-50%,-50%);
box-sizing: border-box;
padding: 70px 30px;
}
h1{
margin: 0;
padding: 0 0 20px;
font-size: 22px;
text-align:center;
}
.loginbox p{
margin: 0;
padding:0;
font-weight: bold;
}
.loginbox input{
width:100%;
margin-bottom: 20px;
}
.loginbox input[type="text"], input[type="password"]{
border: none;
border-bottom: 1px solid #fff;
background: transparent;
outline: none;
height: 40px;
color: #fff;
font-size: 16px;
}
.loginbox input[type="submit"]:hover{
cursor: pointer;
background: #00df00;
color: #000;
}
.loginbox a{
text-decoration: none;
font-size: 12px;
line-height: 20px;
color: darkgray;
}
.loginbox a:hover{
color: #ffc107;
}
.loginbox input[type="submit"]
{
border: none;
outline: none;
height:40px;
background: #00a800;;
font-size: 18px;
border-radius:20px;
}
.avatar{
width: 100px;
height: 100px;
border-radius: 50%;
position: absolute;
top:-50px;
left: calc(50% - 50px);
}
</style>

View File

@ -1,9 +1,29 @@
import {getAuth, onAuthStateChanged} from "firebase/auth"
import app from '../api/firebase';
function isAuth(to, from, next) {
console.log("Checking auth")
const auth = getAuth(app)
onAuthStateChanged(auth, (user) => {
// user is logged in, continue to page
if (user) {
return next()
}
// user is logged out, send back to home page
else {
return next({path: "/"})
}
})
}
function loadPage(component) {
return () => import(`@/pages/${component}.vue`)
}
export default [
{path: "/", component:loadPage("MapPage")},
{path: "/insights", component:loadPage("InsightsPage")},
{path: "/signup", component:loadPage("signup")},
{path: "/login", component:loadPage("loginpage")}
{path: "/secure", component:loadPage('SecurePage'), beforeEnter: isAuth},
{path: "/signup", component:loadPage('SignUpPage')},
{path: "/login", component:loadPage('LoginPage')},
]