3 Commits 270f10d72d ... bdeccc6080

Autor SHA1 Mensaje Fecha
  Ecconia bdeccc6080 Adding application form WIP hace 7 años
  Ecconia eb6d9982f6 Fixing typo in description hace 7 años
  Ecconia 19ffef0261 Saving user-object and restoring it + logout button hace 7 años

+ 1 - 1
public/index.html

@@ -5,7 +5,7 @@
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <meta name="theme-color" content="#111111">
-    <meta name="Description" content="Website of the RedstoneServer. You can create your applications here to be come member. Chat with other members and see who else plays on this server.">
+    <meta name="Description" content="Website of the RedstoneServer. You can create your applications here to become member. Chat with other members and see who else plays on this server.">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
     <title>New RS-Website</title>
   </head>

+ 9 - 2
src/App.vue

@@ -11,7 +11,8 @@
 
 			<div class="user">
 				<div v-if="user">
-					<span>Username: {{ user.username }}</span>
+					<span>Username: {{ user.username }} </span>
+					<span class="rl" @click="logout">Logout</span>
 				</div>
 				<router-link class="rl" to="/login" v-else>Login</router-link>
 			</div>
@@ -45,6 +46,12 @@
 			},
 		},
 
+		methods: {
+			logout() {
+				this.core.logout()
+			}
+		},
+
 		components: {
 			MenuContainer
 		},
@@ -86,7 +93,7 @@
 	}
 
 	header .user {
-		padding: 0.2em 1em;
+		padding: 0.2em 0em;
 	}
 
 	.content {

+ 61 - 0
src/components/SimpleProgressBar.vue

@@ -0,0 +1,61 @@
+<template>
+	<div>
+		<div class="background">
+			<div class="bar" ref="bar"/>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+			}
+		},
+		props: [
+			'count',
+			'max',
+			'steps',
+		],
+		methods: {
+			update: function () {
+				let per = this.count / this.max * 100
+				let bar = this.$refs.bar;
+
+				//Break down into steps.
+				per = Math.floor(per / this.stepsize) * this.stepsize
+
+				bar.style.width = per + '%'
+				bar.style.backgroundColor = per >= 100 ? '#0f0' : '#f00'
+			},
+		},
+		computed: {
+			stepsize() {
+				return 100 / this.steps
+			}
+		},
+		watch: {
+			count: function () {
+				this.update()
+			},
+		}
+	}
+</script>
+
+<style scoped>
+	.bar {
+		height: 3px;
+		min-width: 1%;
+		width: 0%;
+		max-width: 100%;
+		background-color: #f00;
+		transition: width 200ms ease-out;
+	}
+
+	.background {
+		height: 3px;
+		width: 100%;
+		max-width: 60em;
+		background-color: #aaa;
+	}
+</style>

+ 64 - 0
src/components/inputtypes/LimitedTextField.vue

@@ -0,0 +1,64 @@
+<template>
+	<div class="width">
+		<textarea v-bind:class="{ textarea: true, not_enough: highlight && !isEnough, enough: highlight && isEnough }" type="text" v-model="inputText" />
+		<SimpleProgressBar class="progbar" :count="len" max="50" steps="5"/>
+	</div>
+</template>
+
+<script>
+	import SimpleProgressBar from '../SimpleProgressBar.vue'
+
+	export default {
+		data() {
+			return {
+				inputText: '',
+			}
+		},
+
+		props: [
+			'highlight'
+		],
+
+		computed: {
+			isEnough() {
+				return this.inputText.length >= 50
+			},
+			len() {
+				return this.inputText.length
+			}
+		},
+
+		mounted() {
+		},
+
+		components: {
+			SimpleProgressBar,
+		},
+	}
+</script>
+
+<style scoped>
+	.textarea {
+		width: 100%;
+		color: #fff;
+		resize: vertical;
+		min-height: 1.2em;
+		height: 1.2em;
+		border: 1px solid #aaa;
+		margin: auto;
+		background-color: #222;
+	}
+
+	.not_enough {
+		border: 1px solid #f00;
+	}
+
+	.enough {
+		border: 1px solid #0f0;	
+	}
+
+	.width {
+		width: 100%;
+		max-width: 60em;
+	}
+</style>

+ 12 - 0
src/main.js

@@ -9,6 +9,18 @@ Vue.config.productionTip = true
 const core = new Core(store)
 Vue.prototype.core = core
 
+//Update Vuex if localstorage loginstate changed.
+router.beforeEach((from, to, next) => {
+	let user = localStorage.getItem('user')
+	let originalUser = store.state.user
+
+	if(!(user === null && originalUser === null) && (user === null || originalUser === null || user != JSON.stringify(originalUser))) {
+		core.commit('setUser', JSON.parse(user))
+	}
+
+	next()
+})
+
 new Vue({
   router,
   store,

+ 5 - 1
src/router.js

@@ -19,6 +19,10 @@ export default new Router({
 			path: '/login',
 			component: load('Login'),
 		},
+		{
+			path: '/create',
+			component: load('CreateApplication'),
+		},
 		{
 			path: '/impressum',
 			component: load('Impressum')
@@ -42,5 +46,5 @@ export default new Router({
 			path: '*',
 			component: load('NotFound')
 		},
-	]
+	],
 })

+ 7 - 11
src/scripts/core.js

@@ -33,22 +33,18 @@ export default class {
 				})
 	}
 
-	lol(username, password) {
-		//TODO: return promise somehow
-		//alert('Login attempt as user \'' + username + '\' with password \'' + password + '\'')
-
-		/*
-		this.get('/soos')
-			.then(function (response) {
-				console.log('Response: ', response.data)
-			})
-		*/
+	logout() {
+		localStorage.removeItem('user');
+			this.commit('setUser', null)
+	}
 
+	login(username, password) {
+		//TODO: return promise somehow
 		this.post('/login', {
 			username: username,
 			password: password,
 		}).then((response) => {
-			console.log('Response: ', response.data)
+			localStorage.setItem('user', JSON.stringify(response.data));
 			this.commit('setUser', response.data)
 		})
 	}

+ 1 - 1
src/views/Applications.vue

@@ -4,7 +4,7 @@
 		<p>This area is basically the first big GOAL of the final product. Creating and Judging apps. The path to get here is quite long though, many other issues have to be solved first.</p>
 
 		<div v-if="getUser && getUser.rank === undefined">
-			<router-link to="/myapp" v-if="getUser.appstate === 0">Create application.</router-link>
+			<router-link to="/create" v-if="getUser.appstate === 0">Create application.</router-link>
 			<router-link to="/myapp" v-else-if="getUser.appstate === 1">Edit application.</router-link>
 		</div>
 

+ 64 - 0
src/views/CreateApplication.vue

@@ -0,0 +1,64 @@
+<template>
+	<div>
+		<h1>Create application</h1>
+		<div v-if="user">
+			<span>{{ instruction }}</span>
+			<div class="question_block" v-for="(element, index) in pattern" :key="index">
+				<span class="question">{{ element.text }}</span>
+				<span v-if="element.optional"> (Optional)</span>
+				<br>
+				<LimitedTextField class="textfield" :highlight="highlight"></LimitedTextField>
+				<span class="hint">{{ element.hint }}</span>
+			</div>
+			<button @click="update">Create/Update</button>
+		</div>
+		<span v-else>You are not logged in.</span>
+	</div>
+</template>
+
+<script>
+	import LimitedTextField from '../components/inputtypes/LimitedTextField.vue'
+
+	export default {
+		data () {
+			return {
+				instruction: '',
+				pattern: null,
+				highlight: false,
+			}
+		},
+		created () {
+			this.core.get('/app-pattern').then((response) => {
+				this.instruction = response.data.instruction;
+				this.pattern = response.data.fields;
+			})
+		},
+		computed: {
+			user() {
+				return this.$store.state.user
+			},
+		},
+		methods: {
+			update() {
+				this.highlight = true
+			},
+		},
+		components: {
+			LimitedTextField,
+		},
+	}
+</script>
+
+<style scoped>
+	.question_block {
+		margin: 1em;
+	}
+
+	.question {
+		font-weight: bold;
+	}
+
+	.hint {
+		font-size: 0.7em;
+	}
+</style>

+ 2 - 1
src/views/Login.vue

@@ -16,6 +16,7 @@
 </template>
 
 <script>
+	//TODO: Check username for allowed chars and length.
 	export default {
 		data() {
 			return {
@@ -61,7 +62,7 @@
 				return false
 			},
 			attemptLogin() {
-				this.core.lol(this.username, this.password)
+				this.core.login(this.username, this.password)
 			},
 		}
 	}