Skip to content
Snippets Groups Projects
Commit eba52422 authored by Kristian Valset Aars's avatar Kristian Valset Aars
Browse files

Merge branch 'SubjectNav' into 'master'

Subject nav

See merge request !2
parents d535d766 9de7094b
No related branches found
No related tags found
1 merge request!2Subject nav
Pipeline #171531 failed
Showing
with 464 additions and 308 deletions
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "frontend_idatt2105",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"axios": "^0.26.1", "axios": "^0.26.1",
...@@ -12,6 +13,7 @@ ...@@ -12,6 +13,7 @@
"qs": "^6.10.3", "qs": "^6.10.3",
"register-service-worker": "^1.7.2", "register-service-worker": "^1.7.2",
"vue": "^3.2.13", "vue": "^3.2.13",
"vue-mq": "^1.0.1",
"vue-router": "^4.0.3", "vue-router": "^4.0.3",
"vuex": "^4.0.0" "vuex": "^4.0.0"
}, },
...@@ -4198,8 +4200,6 @@ ...@@ -4198,8 +4200,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
"dev": true, "dev": true,
"optional": true,
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0", "json-schema-traverse": "^1.0.0",
...@@ -4215,9 +4215,7 @@ ...@@ -4215,9 +4215,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true, "dev": true
"optional": true,
"peer": true
}, },
"node_modules/ajv-keywords": { "node_modules/ajv-keywords": {
"version": "3.5.2", "version": "3.5.2",
...@@ -10836,6 +10834,14 @@ ...@@ -10836,6 +10834,14 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true "dev": true
}, },
"node_modules/json2mq": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
"integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=",
"dependencies": {
"string-convert": "^0.2.0"
}
},
"node_modules/json5": { "node_modules/json5": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
...@@ -16590,6 +16596,11 @@ ...@@ -16590,6 +16596,11 @@
} }
] ]
}, },
"node_modules/string-convert": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
"integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c="
},
"node_modules/string-length": { "node_modules/string-length": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
...@@ -17594,6 +17605,14 @@ ...@@ -17594,6 +17605,14 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/vue-mq": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/vue-mq/-/vue-mq-1.0.1.tgz",
"integrity": "sha512-FceZ1tFE0MZ8GroRBKPQWBRy4ZEAa7p5R7cGAzJpGuKPU2AI4ClmE+S6O/yV4jO5271o9tgaUFt7fzUAIf9xOQ==",
"dependencies": {
"json2mq": "^0.2.0"
}
},
"node_modules/vue-router": { "node_modules/vue-router": {
"version": "4.0.14", "version": "4.0.14",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.14.tgz", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.14.tgz",
...@@ -21034,6 +21053,7 @@ ...@@ -21034,6 +21053,7 @@
"integrity": "sha512-vf4KqrmuOSnoEYGUiHPeMoxhh6wpiucLWXISn7xYFU80pK1lqcuhbl6tpurAanUIyRO/ENDUQBH7RAdbLNq1bA==", "integrity": "sha512-vf4KqrmuOSnoEYGUiHPeMoxhh6wpiucLWXISn7xYFU80pK1lqcuhbl6tpurAanUIyRO/ENDUQBH7RAdbLNq1bA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/core": "^7.12.16",
"@babel/helper-compilation-targets": "^7.12.16", "@babel/helper-compilation-targets": "^7.12.16",
"@babel/helper-module-imports": "^7.12.13", "@babel/helper-module-imports": "^7.12.13",
"@babel/plugin-proposal-class-properties": "^7.12.13", "@babel/plugin-proposal-class-properties": "^7.12.13",
...@@ -21046,6 +21066,7 @@ ...@@ -21046,6 +21066,7 @@
"@vue/babel-plugin-jsx": "^1.0.3", "@vue/babel-plugin-jsx": "^1.0.3",
"@vue/babel-preset-jsx": "^1.1.2", "@vue/babel-preset-jsx": "^1.1.2",
"babel-plugin-dynamic-import-node": "^2.3.3", "babel-plugin-dynamic-import-node": "^2.3.3",
"core-js": "^3.8.3",
"core-js-compat": "^3.8.3", "core-js-compat": "^3.8.3",
"semver": "^7.3.4" "semver": "^7.3.4"
}, },
...@@ -21213,6 +21234,7 @@ ...@@ -21213,6 +21234,7 @@
"@vue/cli-shared-utils": "^5.0.4", "@vue/cli-shared-utils": "^5.0.4",
"babel-jest": "^27.1.0", "babel-jest": "^27.1.0",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"jest": "^27.1.0",
"jest-serializer-vue": "^2.0.2", "jest-serializer-vue": "^2.0.2",
"jest-transform-stub": "^2.0.0", "jest-transform-stub": "^2.0.0",
"jest-watch-typeahead": "^1.0.0" "jest-watch-typeahead": "^1.0.0"
...@@ -21887,14 +21909,15 @@ ...@@ -21887,14 +21909,15 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"dev": true, "dev": true,
"requires": {}, "requires": {
"ajv": "^8.0.0"
},
"dependencies": { "dependencies": {
"ajv": { "ajv": {
"version": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", "version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
"dev": true, "dev": true,
"optional": true,
"peer": true,
"requires": { "requires": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0", "json-schema-traverse": "^1.0.0",
...@@ -21906,9 +21929,7 @@ ...@@ -21906,9 +21929,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true, "dev": true
"optional": true,
"peer": true
} }
} }
}, },
...@@ -26804,6 +26825,14 @@ ...@@ -26804,6 +26825,14 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true "dev": true
}, },
"json2mq": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
"integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=",
"requires": {
"string-convert": "^0.2.0"
}
},
"json5": { "json5": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
...@@ -30926,6 +30955,11 @@ ...@@ -30926,6 +30955,11 @@
} }
} }
}, },
"string-convert": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
"integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c="
},
"string-length": { "string-length": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
...@@ -31669,6 +31703,14 @@ ...@@ -31669,6 +31703,14 @@
} }
} }
}, },
"vue-mq": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/vue-mq/-/vue-mq-1.0.1.tgz",
"integrity": "sha512-FceZ1tFE0MZ8GroRBKPQWBRy4ZEAa7p5R7cGAzJpGuKPU2AI4ClmE+S6O/yV4jO5271o9tgaUFt7fzUAIf9xOQ==",
"requires": {
"json2mq": "^0.2.0"
}
},
"vue-router": { "vue-router": {
"version": "4.0.14", "version": "4.0.14",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.14.tgz", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.14.tgz",
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
"qs": "^6.10.3", "qs": "^6.10.3",
"register-service-worker": "^1.7.2", "register-service-worker": "^1.7.2",
"vue": "^3.2.13", "vue": "^3.2.13",
"vue-mq": "^1.0.1",
"vue-router": "^4.0.3", "vue-router": "^4.0.3",
"vuex": "^4.0.0" "vuex": "^4.0.0"
}, },
......
<template> <template>
<meta name="viewport" content="user-scalable=no, width=device-width, height=device-height, minimum-scale=1.0, maximum-scale=1.0" />
<div v-if="$store.state.loggedIn" id="nav">
<div v-if="isLoggedIn" id="nav">
<NavBar /> <NavBar />
</div> </div>
<img src="./assets/qsLogo.png" alt="">
<router-view/> <router-view/>
</template> </template>
...@@ -13,63 +18,60 @@ ...@@ -13,63 +18,60 @@
<script> <script>
import NavBar from './components/NavBar.vue' import NavBar from './components/NavBar.vue'
import store from "@/store";
export default { export default {
components: {NavBar}, components: {NavBar},
computed: {
isLoggedIn() {
return this.$store.state.loggedIn
}
}
} }
</script> </script>
<style> <style>
#app { #app {
font-family: Avenir, Helvetica, Arial, sans-serif; font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
text-align: center; text-align: center;
color: #2c3e50; color: #2c3e50;
} margin-left: 10px;
margin-right: 10px;
form {
max-width: 25%; /* was 420px */
margin: 30px auto;
background: white;
text-align: left;
padding: 0px;
border-radius: 10px;
} }
button {
form input { text-decoration: none;
font-size: 20px; background: #00ce89;
border: 0;
padding: 10px 20px;
color: #26323d;
border-radius: 20px;
font-size: 18px;
height: 40px;
} }
label { button:hover {
color: #aaa; background: #2c3e50;
display: inline-block; cursor: pointer;
margin: 25px 0 5px; color: white;
font-size: 0.8em;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: bold;
} }
input { button:active {
display: block; background: #14406c;
padding: 10px 6px; cursor: pointer;
width: 100%; color: white;
box-sizing: border-box;
height: 50px; /* edited */
border: none;
border-bottom: 1px solid #ddd;
color: #555;
} }
button:disabled {
background: #34404d;
cursor: default;
color: #a4a4a4;
}
</style> </style>
src/assets/qsLogo.png

2.83 KiB | W: | H:

src/assets/qsLogo.png

7.19 KiB | W: | H:

src/assets/qsLogo.png
src/assets/qsLogo.png
src/assets/qsLogo.png
src/assets/qsLogo.png
  • 2-up
  • Swipe
  • Onion skin
<template> <template>
<div class="error"> <div class="error">
<h3>Something went wrong</h3> <h3>Error</h3>
<p>{{ errorMessage }}</p> <p>{{ message }}</p>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
props: {
computed: { message: String
errorMessage: {
get() {
return this.$store.state.message
}, },
} }
}
}
</script> </script>
<style scoped> <style scoped>
.error{ .error{
margin: 10, 10;
max-width: 50%;
margin: 30px auto;
margin-top: 0px;
background: white; background: white;
text-align: center; text-align: center;
border-radius: 10px; border-radius: 10px;
border: 2px solid #ff0000; border: 2px solid #de644f;
} }
h3 { h3 {
color: #4038D1; color: #2f2f2f;
text-decoration: underline; text-decoration: underline;
} }
......
...@@ -50,10 +50,7 @@ export default { ...@@ -50,10 +50,7 @@ export default {
border-radius: 4px; border-radius: 4px;
box-shadow: 1px 2px 3px rgba(0,0,0,0.05); box-shadow: 1px 2px 3px rgba(0,0,0,0.05);
border-left: 4px solid #e90074; border-left: 4px solid #e90074;
width: 100%;
background-color: rgb(253, 253, 253); background-color: rgb(253, 253, 253);
width: 100%;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
......
...@@ -23,8 +23,4 @@ export default { ...@@ -23,8 +23,4 @@ export default {
<style> <style>
.exercises {
padding: 10px;
}
</style> </style>
<template> <template>
<div v-if="$store.state.message != ''"> <div class="loginContainer">
<ErrorBox />
<div v-if="error">
<ErrorBox :message="error"/>
</div> </div>
<form @submit.prevent="handleLogin" >
<label>Email:</label> <form @submit.prevent="handleLogin" >
<input type="email" required v-model="email">
<label>Password:</label> <label for="username">Email (NTNU-Email):</label>
<input type="password" required v-model="password"> <input id="username" type="email" required v-model="email">
<div class="loginDiv"> <label for="password">Password:</label>
<button type="button" @click="handleLogin">Login</button> <input type="password" id="password" required v-model="password">
<p @click="forgotPassword" class="forgot">Forgot password?</p>
</div>
<button type="submit" @click="handleLogin">Logg inn</button>
</form> </form>
</div>
</template> </template>
...@@ -30,6 +29,7 @@ export default { ...@@ -30,6 +29,7 @@ export default {
data() { data() {
return { return {
error: null,
email: '', email: '',
password: '', password: '',
token: '' token: ''
...@@ -44,12 +44,17 @@ export default { ...@@ -44,12 +44,17 @@ export default {
this.$store.commit('setToken', ans.data) this.$store.commit('setToken', ans.data)
this.$store.commit('setLogin', this.email, this.password) this.$store.commit('setLogin', this.email, this.password)
this.$store.commit('setMessage', '') this.$store.commit('setMessage', '')
this.$router.push('/Subjects') this.$router.push('/Subjects/student')
}) })
.catch(err => { .catch(err => {
console.log(err) if(err.response) {
this.error = err.response.data;
} else {
this.error = err
}
console.log(err.response)
this.$store.commit('setLogin', '', '') this.$store.commit('setLogin', '', '')
this.$store.commit('setMessage', 'Invalid email or password')
}) })
}, },
...@@ -59,12 +64,53 @@ export default { ...@@ -59,12 +64,53 @@ export default {
} }
}, },
}
</script>
<style>
.loginContainer {
width: 95%;
max-width: 416px;
margin: auto;
}
button {
margin-top: 16px;
width: 100%;
}
form {
margin: 30px auto;
background: white;
text-align: left;
border-radius: 10px;
} }
</script>
<style> form input {
font-size: 20px;
}
label {
color: #333333;
display: inline-block;
margin: 25px 0 5px;
font-size: 0.8em;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: bold;
}
input {
display: block;
padding: 10px 6px;
width: 100%;
box-sizing: border-box;
height: 50px; /* edited */
border: none;
border-bottom: 1px solid #ddd;
color: #414141;
}
</style> </style>
<template> <template>
<div>
<div id="navBar"> <div id="navBar">
<router-link :to="{name: 'Subjects'}">Subjects</router-link> <router-link :to="{name: 'Subjects', params: {tab: 'student'}}">Subjects</router-link>
<router-link :to="{name: 'Settings'}">Settings</router-link> <router-link :to="{name: 'Settings'}">Settings</router-link>
<router-link @click="logOut" :to="{name: 'Login'}">Log out</router-link> <router-link @click="logOut" :to="{name: 'Login'}">Log out</router-link>
</div> </div>
<hr> <hr>
</div>
</template> </template>
<script> <script>
......
<!-- The options navbar 'Student, Stud.ass, Arkivert' --> <!-- The options navbar 'Student, Stud.ass, Arkivert' -->
<template> <template>
<div class="optionBar"> <div class="optionBar">
<a :class="{active: $store.state.currentOption == 'Student'}" @click="$store.commit('setCurrentOption', 'Student')">Student</a> <a :class="{active: this.tab === 'student'}" @click="navigateToTab('student')">Student</a>
<a :class="{active: $store.state.currentOption == 'Stud.ass'}" @click="$store.commit('setCurrentOption', 'Stud.ass')">Stud.ass</a> <a :class="{active: this.tab === 'studentassistant'}" @click="$store.commit('setActiveOption', 'Stud.ass')">Stud.ass</a>
<a :class="{active: $store.state.currentOption == 'Arkivert'}" @click="$store.commit('setCurrentOption', 'Arkivert')">Arkivert</a> <a :class="{active: this.tab === 'archived'}" @click="$store.commit('setActiveOption', 'Arkivert')">Arkivert</a>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
props: {
tab: {
type: String,
required: true
}
},
methods: {
navigateToTab(name) {
this.$router.push({name: 'Subject', params: {tab: name }})
}
}
} }
</script> </script>
......
<template> <template>
<div class="queue"> <div class="queue">
<h1>{{ this.subject_name }}</h1>
<ul> <ul>
<li v-for="student in this.studentQueue" :key="student.student_user_id"> <li v-for="student in this.studentQueue" :key="student.student_user_id">
<Student :student="student" /> <Student :student="student" />
......
<template> <template>
<div class="subjectItemContainer" v-bind:class="{open : subject.active, closed : !subject.active, disabled : !subject.active}">
<div class="subjectHeader"> <div class="subjectHeader">
<h1>{{ subject.subject.subjectInfo.name }}</h1> <h2>{{ subject.subject.subjectInfo.name }}</h2>
<h2>{{ subject.subject.subjectInfo.subject_code }}</h2> <h3>{{ subject.subject_code }} - {{ subject.semester }}</h3>
<h4 v-if="subject.active">Queue is open</h4>
</div> </div>
<div class="subjectOptions"> <div class="subjectOptions">
<button @click="pushToQueueScreen()">View Queue</button>
<div v-if="$store.state.currentOption == 'Student'">
<router-link :to="{ name: 'Info', params: { subject_code: subject.subject_code, semester: subject.semester }}"> <!-- send prop 'subject.exercises' so i can loop it -->
<button @click="$store.commit('setCurrentSubject', subject)">Øvinger</button>
</router-link>
<button>Status</button>
<button @click="chatClick">Chat</button> <button @click="chatClick">Chat</button>
<!--<button @click="">Åpne kø</button>-->
</div> </div>
<div v-else-if="$store.state.currentOption == 'Stud.ass'">
<router-link :to="{ name: 'Info', params: { subject_code: subject.subject_code }}"> <!-- send prop 'subject.exercises' so i can loop it -->
<button @click="$store.commit('setCurrentSubject', subject)">Åpne kø</button>
</router-link>
</div>
</div> </div>
</template> </template>
<script> <script>
import SubjectQueueService from '../service/SubjectService.js'
export default { export default {
props: ['subject'], props: {
subject: {
type: Object,
required: true
}
},
methods: { methods: {
pushToQueueScreen() {
this.$router.push({name: 'Info', params: {subject_code: "IDATT2105", semester: "V22"}})
}
}
}
</script>
<style>
.disabled {
opacity: 75%;
}
.disabled:hover {
opacity: 100%;
}
}, .subjectItemContainer {
background: white;
border-radius: 4px;
box-shadow: 1px 2px 3px rgba(0,0,0,0.05);
border: #e0e0e0 1px solid;
border-left: 10px solid #000000;
display: grid;
padding: 22px;
}
.open {
border-left-color: #59d329;
} }
</script>
<style> .closed {
border-left-color: #e33838;
}
.archived {
border-left-color: #414141;
}
.subjectOptions { .subjectOptions {
text-align: center; text-align: center;
margin: 40px auto; margin: 10px 0 0;
margin-bottom: 15px; display: grid;
grid-auto-flow: column;
} }
.subjectOptions button { .subjectOptions {
display: inline-block; display: grid;
text-decoration: none; grid-row-gap: 10px;
margin: 0 15px; grid-column-gap: 10px;
background: #00ce89;
border: 0;
padding: 10px 20px;
margin-top: 0px;
color: #2c3e50;
border-radius: 20px;
font-size: 20px;
} }
@media only screen and (max-width: 768px) {
.subjectOptions {
grid-auto-flow: row;
}
.subjectOptions button:hover {
background: #2c3e50;
cursor: pointer;
color: white;
} }
</style> </style>
...@@ -24,11 +24,6 @@ export default { ...@@ -24,11 +24,6 @@ export default {
border-radius: 4px; border-radius: 4px;
box-shadow: 1px 2px 3px rgba(233, 7, 101, 0.05); box-shadow: 1px 2px 3px rgba(233, 7, 101, 0.05);
border-left: 4px solid #e90074; border-left: 4px solid #e90074;
width: 100%;
background-color: rgb(253, 253, 253);
display: flex;
width: 100%;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
......
<template>
<div class="container">
<div class="activeQueuesContainer" v-if="this.getActiveSubjects">
<h1>Active Queues</h1>
<ul>
<li v-for="subject in this.getActiveSubjects" :key="subject.subject_code">
<SingleSubject :subject="subject" />
</li>
</ul>
</div>
<div class="inactiveQueuesContainer" v-if="this.getInactiveSubjects">
<h1>Inactive Queues</h1>
<ul>
<li v-for="subject in this.getInactiveSubjects" :key="subject.subject_code">
<SingleSubject :subject="subject" />
</li>
</ul>
</div>
</div>
</template>
<script>
import SubjectService from "@/service/SubjectService";
import SingleSubject from "@/components/SingleSubject";
import store from '@/store/index.js';
export default {
components: {SingleSubject},
data() {
return {
subjects: null
}
},
computed: {
getActiveSubjects() {
if(this.subjects != null) {
return this.subjects.filter(s => {
return s.active && !s.archived;
})
} else {
return null;
}
},
getInactiveSubjects() {
if(this.subjects != null) {
return this.subjects.filter(s => {
return !s.active && !s.archived;
})
} else {
return null;
}
},
},
mounted () {
console.log("Before load")
return SubjectService.getStudentAssistantSubjectQueues(store.state.token)
.then(res => {
console.log(res.data)
this.subjects = res.data;
console.log(this.subjects)
})
.catch(() => next({name: "Error"}))
},
}
</script>
<style>
ul {
padding: 0;
}
li {
list-style-type: none;
margin-bottom: 15px;
}
.container {
max-width: 950px;
margin: 0 auto;
}
.inactiveQueuesContainer {
margin-top: 84px;
}
.container h1 {
text-decoration: underline;
}
</style>
...@@ -4,6 +4,4 @@ import './registerServiceWorker' ...@@ -4,6 +4,4 @@ import './registerServiceWorker'
import router from './router' import router from './router'
import store from './store' import store from './store'
createApp(App).use(store).use(router).mount('#app') createApp(App).use(store).use(router).mount('#app')
...@@ -4,7 +4,7 @@ import Settings from '../views/Settings.vue' ...@@ -4,7 +4,7 @@ import Settings from '../views/Settings.vue'
import Subjects from '../views/Subjects.vue' import Subjects from '../views/Subjects.vue'
import NotFound from '../views/NotFound.vue' import NotFound from '../views/NotFound.vue'
import Info from '../views/Info.vue' import Info from '../views/Info.vue'
import store from "@/store";
const routes = [ const routes = [
{ {
...@@ -15,19 +15,28 @@ const routes = [ ...@@ -15,19 +15,28 @@ const routes = [
{ {
path: '/Settings', path: '/Settings',
name: 'Settings', name: 'Settings',
component: Settings component: Settings,
meta: {
requiresAuth: true
}
}, },
{ {
path: '/Subjects', path: '/Subjects/:tab',
name: 'Subjects', name: 'Subjects',
component: Subjects component: Subjects,
meta: {
requiresAuth: true
}
}, },
{ {
//path: '/Subjects/Exercises/:subject_id', // dynamic path //path: '/Subjects/Exercises/:subject_id', // dynamic path
path: '/Subjects/:subject_code/:semester/Info', path: '/Subjects/:subject_code/:semester/Info',
name: 'Info', name: 'Info',
component: Info component: Info,
meta: {
requiresAuth: true
}
}, },
// Redirect any none-existing path to 404 page // Redirect any none-existing path to 404 page
{ {
...@@ -42,4 +51,17 @@ const router = createRouter({ ...@@ -42,4 +51,17 @@ const router = createRouter({
routes routes
}) })
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (store.state.token === '') {
next({ name: 'Login' })
} else {
next()
}
} else {
next()
}
})
export default router export default router
...@@ -3,10 +3,8 @@ import { createStore } from 'vuex' ...@@ -3,10 +3,8 @@ import { createStore } from 'vuex'
export default createStore({ export default createStore({
state: { // variables accessable from anywhere within the app state: { // variables accessable from anywhere within the app
currentView:'', // den her currentView:'', // den her
Email: '', // den her Email: '', // den her
password: '', // den her
token: '', token: '',
loggedIn: false, // den her loggedIn: false, // den her
forgotPassword: false, forgotPassword: false,
...@@ -17,27 +15,12 @@ export default createStore({ ...@@ -17,27 +15,12 @@ export default createStore({
}, },
getters: { // data from state can be accessed directly. But with getters we can do some filtering before getting the returned value(s).
getSubject(code, semester) {
for(subject in subjects) {
if(subject.semester == semester && subject.subjectInfo.subject_code == code) {
return subject
}
}
return null
}
},
mutations: { // methods to change variables within the state mutations: { // methods to change variables within the state
setEmail(state, newEmail) { setEmail(state, newEmail) {
state.currentEmail = newEmail state.currentEmail = newEmail
}, },
setPassword(state, newPassword) {
state.currentPassword = newPassword
},
setPassword(state) {
state.forgotPassword = !state.forgotPassword
state.message = ''
},
setCurrentSubject(state, subject) { setCurrentSubject(state, subject) {
state.currentSubject = subject state.currentSubject = subject
}, },
......
<template> <template>
<div class="info"> <div class="info">
<div class="queue"> <div class="queue">
<h2>{{ this.subject_name }}</h2>
<Queue :studentQueue="studentQueue" /> <Queue :studentQueue="studentQueue" />
</div> </div>
<div class="exercises"> <div class="exercises">
<h2>{{ this.subject_name }}</h2>
<Exercises :exercises="exercises" :subject="subject"/> <Exercises :exercises="exercises" :subject="subject"/>
</div> </div>
...@@ -95,28 +94,20 @@ export default { ...@@ -95,28 +94,20 @@ export default {
<style> <style>
.info { .info {
width: 100%; display: grid;
display: inline-block; grid-auto-flow: column;
width: 100%; grid-column-gap: 32px;
display: flex;
flex-direction: row;
justify-content: center;
} }
@media only screen and (max-width: 768px) {
.queue { .info {
margin: 30px; grid-auto-flow: row;
padding: 10px; grid-column-gap: 10px;
} }
.exercises {
margin: 30px;
margin-left: 100px;
} }
</style> </style>
<template> <template>
<img src="../assets/qsLogo.png" alt="">
<div v-if="$store.state.forgotPassword"> <div v-if="$store.state.forgotPassword">
<ForgotPassword /> <ForgotPassword />
</div> </div>
<div v-else> <div v-else>
<LoginForm /> <LoginForm />
</div> </div>
...@@ -30,41 +30,5 @@ export default { ...@@ -30,41 +30,5 @@ export default {
<style> <style>
.loginDiv button{
background: #4038D1;
border: 0;
padding: 10px 20px;
margin-top: 20px;
color: white;
border-radius: 20px;
font-size: 20px;
}
.loginDiv button:hover {
cursor: pointer;
background: #1e59b1;
}
.loginDiv {
width: 100%;
display: flex;
flex-direction: row;
position: relative;
}
.forgot {
position: absolute;
right: 0;
top: 12px;
color: #4038D1;
text-decoration: underline;
font-size: 20px;
}
.forgot:hover {
cursor: pointer;
color: #1e59b1;
}
</style> </style>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment