Skip to content

Commit

Permalink
Merge pull request #40 from stanislawK/35_login_component
Browse files Browse the repository at this point in the history
[35] login component
  • Loading branch information
stanislawK authored Apr 3, 2019
2 parents 84b60db + dfa365e commit 1f31ba3
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 80 deletions.
2 changes: 2 additions & 0 deletions backend/app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from flask import Flask
from flask_cors import CORS

from backend.extensions import db, migrate, jwt
from backend.blueprints import auth
Expand All @@ -9,6 +10,7 @@ def create_app():
app = Flask(__name__)
app.config.from_object('backend.config.DevelopmentConfig')

CORS(app)
initialize_extensions(app)
register_blueprints(app)

Expand Down
1 change: 1 addition & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ psycopg2==2.7.6
pytest==4.1.0
marshmallow==3.0.0rc1
flask-jwt-extended==3.14.0
flask-cors==3.0.7
7 changes: 6 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"vue": "2.5.17"
"axios": "0.18.0",
"vue": "2.5.17",
"vue-router": "3.0.2",
"vuelidate": "0.7.4",
"vuetify": "1.4.0",
"vuex": "3.0.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "3.1.1",
Expand Down
1 change: 1 addition & 0 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link href='https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons' rel="stylesheet">
<title>frontend</title>
</head>
<body>
Expand Down
23 changes: 3 additions & 20 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,11 @@
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<div>
<router-view></router-view>
</div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
components: {
HelloWorld
}
name: 'app'
}
</script>

<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
58 changes: 0 additions & 58 deletions frontend/src/components/HelloWorld.vue

This file was deleted.

15 changes: 15 additions & 0 deletions frontend/src/components/HomePage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<div>
<v-app>
</v-app>
</div>
</template>

<script>
export default {
}
</script>

<style lang="css">
</style>
140 changes: 140 additions & 0 deletions frontend/src/components/Login.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<template>
<div class="register-form">
<v-app id="login">
<v-layout justify-center>
<v-flex xs12 sm6>
<v-alert
type="error"
:value="error_msg ? true : false"
@click="error_msg=''"
transition="slide-y-transition"
>{{error_msg}}</v-alert>
<v-alert
type="success"
:value="successAlert"
@click="successAlert = !successAlert"
transition="slide-y-transition"
>Pomyślnie zalogowano</v-alert>
<v-progress-circular
v-if="spinner"
:size="50"
color="green"
indeterminate>
</v-progress-circular>
<form>
<v-text-field
v-model="username"
label="Nazwa użytkownika"
required
:error-messages="usernameErrors"
@input="$v.username.$touch()"
@blur="$v.username.$touch()"
></v-text-field>
<v-text-field
v-model="password"
label="Hasło"
:append-icon="showPass ? 'visibility_off' : 'visibility'"
:type="showPass ? 'text' : 'password'"
@click:append="showPass = !showPass"
required
:error-messages="passwordErrors"
@input="$v.password.$touch()"
@blur="$v.password.$touch()"
></v-text-field>
<v-btn @click="onSubmit">Zaloguj</v-btn>
</form>
</v-flex>
</v-layout>
</v-app>
</div>
</template>

<script>
import { minLength, required } from 'vuelidate/lib/validators'
export default {
data() {
return {
username: '',
password: '',
showPass: false,
error_msg: '',
successAlert: false,
showSpinner: false
}
},
validations: {
username: { required, minLength: minLength(5) },
password: { required }
},
methods: {
onSubmit() {
const loginData = {
username: this.username,
password: this.password
}
this.error_msg = ''
if(!this.$v.$invalid) {
this.spinner = true
this.$store.dispatch('auth/login', loginData)
.then( res => {
this.spinner = false
this.clearForm()
if (res.status == 201) this.successAlert = true;
}, error => {
this.spinner = false
this.clearForm()
const err = error.response.data.msg
if (err == "Not authorized") {
this.error_msg = "Nieprawidłowa nazwa użytkownika, lub hasło"
} else if (err.includes('User already logged in')) {
this.error_msg = "Jesteś już zalogowany"
} else if (error) {
this.error_msg = "Logowanie nie powiodło się"
}
})
}
},
clearForm() {
this.$v.$reset()
this.username = ''
this.password = ''
}
},
computed: {
usernameErrors() {
const errors = []
if (!this.$v.username.$dirty) return errors
!this.$v.username.minLength && errors.push(
'Wprowadź poprawną nazwę użytkownika'
)
!this.$v.username.required && errors.push(
'Nazwa użytkownika jest wymagana'
)
return errors
},
passwordErrors() {
const errors = []
if (!this.$v.password.$dirty) return errors
!this.$v.password.required && errors.push(
'Hasło jest wymagane'
)
return errors
},
},
}
</script>

<style>
.v-messages__message {
padding: 2px;
}
#login {
margin-top: 20vh;
margin-left: 2em;
margin-right: 2em;
}
</style>
11 changes: 11 additions & 0 deletions frontend/src/main.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import Vue from 'vue'
import App from './App.vue'
import Vuelidate from 'vuelidate'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.min.css'

import router from './router'
import store from './store'

Vue.use(Vuelidate)
Vue.use(Vuetify)

Vue.config.productionTip = false

new Vue({
router,
store,
render: h => h(App),
}).$mount('#app')
14 changes: 14 additions & 0 deletions frontend/src/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Vue from 'vue'
import VueRouter from 'vue-router'

import HomePage from './components/HomePage.vue'
import Login from './components/Login.vue'

Vue.use(VueRouter)

const routes = [
{ path: '/', component: HomePage },
{ path: '/login', component: Login }
]

export default new VueRouter({mode: 'history', routes})
18 changes: 18 additions & 0 deletions frontend/src/store/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Vue from 'vue';
import Vuex from 'vuex';
import auth from './modules/auth'

Vue.use(Vuex);

const store = new Vuex.Store({
state: {},
getters: {},
mutations: {},
actions : {},

modules: {
auth
}
})

export default store;
37 changes: 37 additions & 0 deletions frontend/src/store/modules/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import axios from 'axios';
axios.defaults.baseURL = 'http://0.0.0.0:5000/'

export default {
namespaced: true,
state: {
token: localStorage.getItem('token') || '',
},
getters: {
isLoggedIn: state => !!state.token,
},
mutations: {
auth_success(state, token) {
state.token = token
}
},
actions: {
login({commit, dispatch}, loginData) {
return new Promise ((resolve, reject) => {
axios.post('auth/login', {
username: loginData.username,
password: loginData.password
})
.then( res => {
const token = res.data.access_token
localStorage.setItem('token', token)
axios.defaults.headers.common['Authorization'] = 'Bearer ' + token
commit('auth_success', token)
resolve(res)
}, error => {
localStorage.removeItem('token')
reject(error)
})
})
}
}
}
Loading

0 comments on commit 1f31ba3

Please sign in to comment.