comparison client/src/login/Login.vue @ 585:ef307bd6b5d8

refac: restructured client application To make the application more accessible for developers, the structure was reorganized. Instead of sticking to technical terminology, the application terminology is according to the domain: I.e. "map" contains everything regarding map (including store).
author Thomas Junk <thomas.junk@intevation.de>
date Fri, 07 Sep 2018 11:13:56 +0200
parents
children 51dc26b0f066
comparison
equal deleted inserted replaced
584:8b66a10aaf8a 585:ef307bd6b5d8
1 (<template>
2 <div class="d-flex flex-column login shadow-lg">
3 <div class="loginmask">
4 <!-- logo section -->
5 <div class="d-flex flex-row justify-content-center mb-3">
6 <div class="logo"><img src="../application/assets/logo.png"></div>
7 <div class="title">
8 <h1>{{ appTitle }}</h1>
9 </div>
10 </div>
11 <!-- end logo section -->
12 <form class="loginform" @submit.prevent="login">
13 <div id="alert" :style="errorMessageStyle" :class="errorMessageClass" role="alert">
14 <span>{{ errorMessage }}</span>
15 </div>
16 <div class="input-group mb-3">
17 <input type="text" v-model="user" id="inputUsername" class="form-control shadow-sm" :placeholder="usernameLabel" required autofocus>
18 </div>
19 <div class="input-group mb-3">
20 <input :type="isPasswordVisible" v-model="password" id="inputPassword" class="form-control shadow-sm" :placeholder='passwordLabel' :required='!showPasswordReset' :disabled='showPasswordReset'>
21 <div class="input-group-append">
22 <span class="input-group-text disabled" id="basic-addon2" @click="showPassword">
23 <i :class="eyeIcon"></i>
24 </span>
25 </div>
26 </div>
27 <button v-if="showPasswordReset==false" class="btn btn-primary btn-block shadow-sm" :disabled="submitted || showPasswordReset" type="submit">
28 <translate>Login</translate>
29 </button>
30 <div v-if="showPasswordReset" class="passwordreset">
31 <button class="btn btn-block btn-info" type="button" @click="resetPassword">
32 <translate>Request password reset!</translate>
33 </button>
34 <div class="pull-right">
35 <a href="#" @click.prevent="togglePasswordReset">
36 <translate>back to login</translate>
37 </a>
38 </div>
39 </div>
40 <div v-else class="pull-right">
41 <a href="#" @click.prevent="togglePasswordReset">
42 <translate>Forgot password</translate>
43 </a>
44 </div>
45 </form>
46
47 <!-- bottom logo section -->
48 <div class="mb-3 secondary-logo"><img :src="secondaryLogo"></div>
49 </div>
50 </div>
51 </template>)
52
53 <style lang="scss">
54 @import "../application/assets/application.scss";
55
56 .login {
57 background-color: white;
58 min-width: 375px;
59 min-height: 500px;
60 @extend %fully-centered;
61 }
62
63 .loginform {
64 max-width: 375px;
65 margin-left: auto;
66 margin-right: auto;
67 }
68
69 .loginmask {
70 margin-left: $large-offset;
71 margin-right: $large-offset;
72 margin-top: $large-offset;
73 }
74
75 .logo {
76 margin-right: $offset;
77 }
78
79 .alert {
80 padding: 0.5rem;
81 }
82
83 .secondary-logo {
84 max-width: 375px;
85 margin-left: auto;
86 margin-right: auto;
87 margin-bottom: auto;
88 }
89 </style>
90
91 <script>
92 import { mapGetters } from "vuex";
93 import { HTTP } from "../application/lib/http.js";
94 import { displayError } from "../application/lib/errors.js";
95
96 export default {
97 name: "login",
98 data() {
99 return {
100 user: "",
101 password: "",
102 submitted: false,
103 loginFailed: false,
104 passwordJustResetted: false,
105 readablePassword: false,
106 showPasswordReset: false,
107 usernameToReset: ""
108 };
109 },
110 computed: {
111 errorMessage() {
112 if (this.loginFailed) return this.$gettext("Login failed");
113 if (this.passwordJustResetted)
114 return this.$gettext("Password reset requested!");
115 return "&npsp;";
116 },
117 passwordLabel() {
118 return this.$gettext("Enter passphrase");
119 },
120 usernameLabel() {
121 return this.$gettext("Enter username");
122 },
123 isPasswordVisible() {
124 return this.readablePassword ? "text" : "password";
125 },
126 eyeIcon() {
127 return {
128 fa: true,
129 "fa-eye": !this.readablePassword,
130 "fa-eye-slash": this.readablePassword
131 };
132 },
133 errorMessageStyle() {
134 if (this.loginFailed || this.passwordJustResetted) {
135 return "visibility:visible";
136 }
137 return "visibility:hidden";
138 },
139 errorMessageClass() {
140 let result = {
141 "mb-3": true,
142 errormessage: true,
143 alert: true
144 };
145 if (this.loginFailed) {
146 result["alert-danger"] = true;
147 }
148 if (this.passwordJustResetted) {
149 result["alert-info"] = true;
150 }
151 return result;
152 },
153 ...mapGetters("application", ["appTitle", "secondaryLogo"])
154 },
155 methods: {
156 login() {
157 this.submitted = true;
158 this.passwordJustResetted = false;
159 const { user, password } = this;
160 this.$store
161 .dispatch("user/login", { user, password })
162 .then(() => {
163 this.loginFailed = false;
164 this.$router.push("/");
165 })
166 .catch(error => {
167 this.loginFailed = true;
168 this.submitted = false;
169 const { status, data } = error.response;
170 displayError({
171 title: "Backend Error",
172 message: `${status}: ${data.message || data}`
173 });
174 });
175 },
176 showPassword() {
177 // disallowing toggle when in reset mode
178 if (this.showPasswordReset) return;
179 this.readablePassword = !this.readablePassword;
180 },
181 togglePasswordReset() {
182 this.passwordJustResetted = false;
183 this.showPasswordReset = !this.showPasswordReset;
184 this.loginFailed = false;
185 },
186 resetPassword() {
187 if (this.user) {
188 HTTP.post("/users/passwordreset", { user: this.user }).catch(error => {
189 const { status, data } = error.response;
190 displayError({
191 title: "Backend Error",
192 message: `${status}: ${data.message || data}`
193 });
194 });
195 this.togglePasswordReset();
196 this.passwordJustResetted = true;
197 }
198 }
199 }
200 };
201 </script>