comparison client/src/usermanagement/Userdetail.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 8278b2fb0c33
comparison
equal deleted inserted replaced
584:8b66a10aaf8a 585:ef307bd6b5d8
1 <template>
2 <div class="userdetails shadow fadeIn animated">
3 <div class="card">
4 <div class="card-header shadow-sm text-white bg-info mb-3">
5 {{ this.cardHeader }}
6 <span @click="closeDetailview" class="pull-right">
7 <i class="fa fa-close"></i>
8 </span>
9 </div>
10 <div class="card-body">
11 <form @submit.prevent="save">
12 <div class="formfields">
13 <div v-if="currentUser.isNew" class="form-group row">
14 <label for="user">Username</label>
15 <input type="user" :placeholder="userNamePlaceholder" class="form-control form-control-sm" id="user" aria-describedby="userHelp" v-model="currentUser.user">
16 <div v-show="errors.user" class="text-danger">
17 <small>
18 <i class="fa fa-warning"></i> {{ errors.user }}</small>
19 </div>
20 </div>
21 <div class="form-group row">
22 <label for="country">Country</label>
23 <select class="form-control form-control-sm" v-on:change="validateCountry" v-model="currentUser.country">
24 <option disabled value="">Please select one</option>
25 <option v-for="country in countries" v-bind:value="country" v-bind:key="country">{{country}}</option>
26 </select>
27 <div v-show="errors.country" class="text-danger">
28 <small>
29 <i class="fa fa-warning"></i> {{ errors.country }}</small>
30 </div>
31 </div>
32 <div class="form-group row">
33 <label for="email">Email address</label>
34 <input type="email" v-on:change="validateEmailaddress" class="form-control form-control-sm" id="email" aria-describedby="emailHelp" v-model="currentUser.email">
35 <div v-show="errors.email" class="text-danger">
36 <small>
37 <i class="fa fa-warning"></i> {{ errors.email }}</small>
38 </div>
39 </div>
40 <div class="form-group row">
41 <label for="role">Role</label>
42 <select class="form-control form-control-sm" v-on:change="validateRole" v-model="currentUser.role">
43 <option disabled value="">Please select one</option>
44 <option value="sys_admin">Sysadmin</option>
45 <option value="waterway_admin">Waterway Admin</option>
46 <option value="waterway_user">Waterway User</option>
47 </select>
48 <div v-show="errors.role" class="text-danger">
49 <small>
50 <i class="fa fa-warning"></i> {{ errors.role }}</small>
51 </div>
52 </div>
53 <div class="form-group row">
54 <PasswordField @fieldchange="passwordChanged" :placeholder="passwordPlaceholder" :label="passwordLabel" :passworderrors="errors.password"></PasswordField>
55 </div>
56 <div class="form-group row">
57 <PasswordField @fieldchange="passwordReChanged" :placeholder="passwordRePlaceholder" :label="passwordReLabel" :passworderrors="errors.passwordre"></PasswordField>
58 </div>
59 </div>
60 <div>
61 <button type="submit" :disabled="submitted" class="shadow-sm btn btn-info pull-right">Submit</button>
62 </div>
63 </form>
64 </div>
65 </div>
66 </div>
67 </template>
68
69 <style lang="scss">
70 @import "../application/assets/application.scss";
71
72 .formfields {
73 width: 10vw;
74 }
75
76 .userdetails {
77 margin-top: $topbarheight;
78 min-width: 40vw;
79 margin-right: auto;
80 height: 100%;
81 }
82
83 form {
84 margin-left: $offset;
85 font-size: 0.9rem;
86 }
87 </style>
88 <script>
89 import { displayError } from "../application/lib/errors.js";
90 import { mapGetters } from "vuex";
91 import PasswordField from "./Passwordfield";
92
93 const emptyErrormessages = () => {
94 return {
95 email: "",
96 country: "",
97 role: "",
98 password: "",
99 passwordre: ""
100 };
101 };
102
103 const isEmailValid = email => {
104 /**
105 *
106 * For convenience purposes the same regex used as in the go code
107 * cf. types.go
108 *
109 */
110 // eslint-disable-next-line
111 return /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/.test(
112 email
113 );
114 };
115
116 const violatedPasswordRules = password => {
117 return (
118 // rules according to issue 70
119 password.length < 7 ||
120 /\W/.test(password) == false ||
121 /\d/.test(password) == false
122 );
123 };
124
125 export default {
126 name: "userdetail",
127 components: {
128 PasswordField
129 },
130 data() {
131 return {
132 passwordLabel: "Password",
133 passwordReLabel: "Repeat Password",
134 passwordPlaceholder: "password",
135 passwordRePlaceholder: "password again",
136 password: "",
137 passwordre: "",
138 currentUser: {},
139 path: null,
140 submitted: false,
141 errors: {
142 email: "",
143 country: "",
144 role: "",
145 password: "",
146 passwordre: ""
147 }
148 };
149 },
150 mounted() {
151 this.currentUser = { ...this.user };
152 this.path = this.user.name;
153 },
154 watch: {
155 user() {
156 this.currentUser = { ...this.user };
157 this.path = this.user.name;
158 this.clearPassword();
159 this.clearErrors();
160 }
161 },
162 computed: {
163 cardHeader() {
164 if (this.currentUser.isNew) return "N.N";
165 return this.currentUser.user;
166 },
167 userNamePlaceholder() {
168 if (this.currentUser.isNew) return "N.N";
169 return "";
170 },
171 ...mapGetters("application", ["countries"]),
172 user() {
173 return this.$store.getters["usermanagement/currentUser"];
174 },
175 isFormValid() {
176 return (
177 isEmailValid(this.currentUser.email) &&
178 this.currentUser.country &&
179 this.password === this.passwordre &&
180 (this.password === "" || !violatedPasswordRules(this.password))
181 );
182 }
183 },
184 methods: {
185 passwordChanged(value) {
186 this.password = value;
187 this.validatePassword();
188 },
189 passwordReChanged(value) {
190 this.passwordre = value;
191 this.validatePassword();
192 },
193 clearErrors() {
194 this.errors = emptyErrormessages();
195 },
196 clearPassword() {
197 this.password = "";
198 this.passwordre = "";
199 },
200 closeDetailview() {
201 this.$store.commit("usermanagement/clearCurrentUser");
202 this.$store.commit("usermanagement/setUserDetailsInvisible");
203 },
204 validateCountry() {
205 this.errors.country = this.currentUser.country
206 ? ""
207 : "Please choose a country";
208 },
209 validateRole() {
210 this.errors.role = this.currentUser.role ? "" : "Please choose a role";
211 },
212 validatePassword() {
213 this.errors.passwordre =
214 this.password === this.passwordre ? "" : "Passwords do not match!";
215 this.errors.password =
216 this.password === "" || !violatedPasswordRules(this.password)
217 ? ""
218 : "Password should at least be 8 char long including 1 digit and 1 special char like $";
219 },
220 validateEmailaddress() {
221 this.errors.email = isEmailValid(this.currentUser.email)
222 ? ""
223 : "invalid email";
224 },
225 validate() {
226 this.validateCountry();
227 this.validateRole();
228 this.validatePassword();
229 this.validateEmailaddress();
230 },
231 save() {
232 this.validate();
233 if (!this.isFormValid) return;
234 if (this.password) this.currentUser.password = this.password;
235 this.submitted = true;
236 this.$store
237 .dispatch("usermanagement/saveCurrentUser", {
238 path: this.user.user,
239 user: this.currentUser
240 })
241 .then(() => {
242 this.submitted = false;
243 this.$store.dispatch("usermanagement/loadUsers").catch(error => {
244 const { status, data } = error.response;
245 displayError({
246 title: "Backend Error",
247 message: `${status}: ${data.message || data}`
248 });
249 });
250 })
251 .catch(error => {
252 this.submitted = false;
253 const { status, data } = error.response;
254 displayError({
255 title: "Error while saving user",
256 message: `${status}: ${data.message || data}`
257 });
258 });
259 }
260 }
261 };
262 </script>