Skip to content

Commit e5b3823

Browse files
committed
feat(webapp): create generic password field
1 parent 34ce1be commit e5b3823

File tree

5 files changed

+122
-75
lines changed

5 files changed

+122
-75
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<template>
2+
<v-text-field
3+
v-bind="computedProps"
4+
v-on="$listeners"
5+
@click:append="toggleHide()"
6+
/>
7+
</template>
8+
9+
<script>
10+
import {mdiEye, mdiEyeOff, mdiKey} from '@mdi/js';
11+
import {VTextField} from 'vuetify/lib/components';
12+
13+
export default {
14+
name: 'GenericPassword',
15+
extends: VTextField,
16+
props: {
17+
errorMessages: {
18+
type: [String, Array],
19+
default: () => [],
20+
},
21+
label: {
22+
type: String,
23+
required: false,
24+
},
25+
required: {
26+
type: Boolean,
27+
default: true,
28+
},
29+
standalone: {
30+
type: Boolean,
31+
default: false,
32+
},
33+
new: {
34+
type: Boolean,
35+
required: false,
36+
},
37+
},
38+
data() {
39+
return {
40+
hide_password: true,
41+
};
42+
},
43+
computed: {
44+
computedProps() {
45+
const icon = mdiKey;
46+
const iconToggle = this.hide_password ? mdiEyeOff : mdiEye;
47+
let label = 'Password';
48+
if(!this.required) {
49+
label += ' (Optional)';
50+
}
51+
if(this.new) {
52+
label = 'New ' + label;
53+
}
54+
if(this.label) { // override with custom label
55+
label = this.label;
56+
}
57+
const ruleDefs = {
58+
required: v => !!v || 'Password is required.',
59+
min: v => (v !== undefined && v.length >= 8) || 'Min 8 characters',
60+
};
61+
let rules = []
62+
if(this.required) {
63+
rules.push(ruleDefs.required)
64+
}
65+
if(this.new) {
66+
rules.push(ruleDefs.min)
67+
}
68+
return {
69+
...this.$props,
70+
type: this.hide_password ? 'password' : 'text',
71+
label: label,
72+
autocomplete: this.new ? 'new-password' : '',
73+
prependIcon: this.standalone ? '' : icon,
74+
prependInnerIcon: this.standalone ? icon : '',
75+
appendIcon: iconToggle,
76+
flat: this.standalone,
77+
solo: this.standalone,
78+
outlined: true,
79+
rules: rules,
80+
errorMessages: this.errorMessages,
81+
validateOnInput: true,
82+
}
83+
}
84+
},
85+
methods: {
86+
toggleHide() {
87+
this.hide_password = !this.hide_password;
88+
}
89+
},
90+
};
91+
</script>
Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
<template>
22
<div>
33
<div class="text-center" v-if="!success">
4-
<v-text-field
5-
v-model="payload.new_password"
6-
:append-icon="show ? 'mdi-eye' : 'mdi-eye-off'"
7-
label="New password"
8-
required
9-
:disabled="working"
10-
:rules="[rules.required, rules.min]"
11-
:type="show ? 'text' : 'password'"
12-
hint="At least 8 characters"
13-
autocomplete="new-password"
14-
@click:append="show = !show"
15-
tabindex="1"
16-
></v-text-field>
4+
<generic-password
5+
v-model="payload.new_password"
6+
:autofocus="true"
7+
:new="true"
8+
:standalone="true"
9+
tabindex="1"
10+
/>
1711
<v-btn
1812
depressed
1913
color="primary"
@@ -31,16 +25,11 @@
3125

3226
<script>
3327
import GenericActionHandler from "./GenericActionHandler.vue"
28+
import GenericPassword from "@/components/Field/GenericPassword.vue";
3429
3530
export default {
3631
name: 'ResetPasswordActionHandler',
32+
components: {GenericPassword},
3733
extends: GenericActionHandler,
38-
data: () => ({
39-
rules: {
40-
required: value => !!value || 'Required.',
41-
min: v => (v !== undefined && v.length >= 8) || 'Min 8 characters',
42-
},
43-
show: false,
44-
}),
4534
};
4635
</script>

www/webapp/src/views/ChangeEmail.vue

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,13 @@
4040
label="Current Email Address"
4141
:readonly="true"
4242
/>
43-
<v-text-field
44-
v-model="password"
45-
:append-icon="show ? 'mdi-eye' : 'mdi-eye-off'"
46-
prepend-icon="mdi-blank"
47-
outlined
48-
label="Password"
49-
required
50-
:rules="[rules.required]"
51-
:type="show ? 'text' : 'password'"
52-
:error-messages="password_errors"
53-
@change="password_errors=[]"
54-
@click:append="show = !show"
55-
ref="password"
56-
tabindex="1"
57-
></v-text-field>
43+
44+
<generic-password
45+
v-model="password"
46+
ref="password"
47+
tabindex="1"
48+
/>
49+
5850
<generic-email
5951
v-model="new_email"
6052
:new="true"
@@ -82,11 +74,13 @@
8274
import { HTTP, withWorking ,digestError} from '@/utils';
8375
import ErrorAlert from "@/components/ErrorAlert.vue";
8476
import GenericEmail from "@/components/Field/GenericEmail.vue";
77+
import GenericPassword from "@/components/Field/GenericPassword.vue";
8578
8679
export default {
8780
name: 'ChangeEmail',
8881
components: {
8982
GenericEmail,
83+
GenericPassword,
9084
ErrorAlert,
9185
},
9286
data: () => ({
@@ -102,7 +96,6 @@
10296
10397
/* password field */
10498
password: '',
105-
password_errors: [],
10699
107100
/* email field */
108101
new_email: '',

www/webapp/src/views/DeleteAccount.vue

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,13 @@
3838
label="Current Email Address"
3939
:readonly="true"
4040
/>
41-
<v-text-field
42-
v-model="password"
43-
:append-icon="show ? 'mdi-eye' : 'mdi-eye-off'"
44-
prepend-icon="mdi-blank"
45-
outlined
46-
label="Password"
47-
required
48-
:rules="[rules.required]"
49-
:type="show ? 'text' : 'password'"
50-
:error-messages="password_errors"
51-
@change="password_errors=[]"
52-
@click:append="show = !show"
53-
ref="password"
54-
tabindex="1"
55-
></v-text-field>
41+
42+
<generic-password
43+
v-model="password"
44+
:autofocus="true"
45+
ref="password"
46+
tabindex="1"
47+
/>
5648
</v-card-text>
5749
<v-card-actions class="justify-center">
5850
<v-btn
@@ -75,28 +67,21 @@
7567
import { HTTP, withWorking, digestError } from '@/utils';
7668
import ErrorAlert from "@/components/ErrorAlert.vue";
7769
import GenericEmail from "@/components/Field/GenericEmail.vue";
70+
import GenericPassword from "@/components/Field/GenericPassword.vue";
7871
7972
export default {
8073
name: 'DeleteAccount',
81-
components: {GenericEmail, ErrorAlert},
74+
components: {GenericEmail, GenericPassword, ErrorAlert},
8275
data: () => ({
8376
valid: false,
8477
working: false,
8578
done: false,
8679
errors: [],
8780
email: '',
88-
rules: {
89-
required: v => !!v || 'Required.',
90-
},
91-
show: false,
9281
9382
/* password field */
9483
password: '',
95-
password_errors: [],
9684
}),
97-
mounted() {
98-
this.initialFocus();
99-
},
10085
async created() {
10186
const self = this;
10287
await withWorking(this.error, () => HTTP
@@ -105,9 +90,6 @@
10590
);
10691
},
10792
methods: {
108-
initialFocus() {
109-
return this.$refs.password.focus();
110-
},
11193
async deleteAccount() {
11294
if (!this.$refs.form.validate()) {
11395
return;

www/webapp/src/views/LoginPage.vue

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,9 @@
3232
:autofocus="true"
3333
tabindex="1"
3434
/>
35-
<v-text-field
35+
<generic-password
3636
v-model="password"
37-
label="Password"
38-
:append-icon="hide_password ? 'mdi-eye' : 'mdi-eye-off'"
39-
:type="hide_password ? 'password' : 'text'"
40-
outlined
41-
required
42-
:rules="password_rules"
4337
tabindex="2"
44-
@click:append="() => (hide_password = !hide_password)"
4538
/>
4639
<v-layout class="justify-center">
4740
<v-checkbox
@@ -85,11 +78,13 @@ import { HTTP, digestError } from '@/utils';
8578
import ErrorAlert from "@/components/ErrorAlert.vue";
8679
import {useUserStore} from "@/store/user";
8780
import GenericEmail from "@/components/Field/GenericEmail.vue";
81+
import GenericPassword from "@/components/Field/GenericPassword.vue";
8882
8983
export default {
9084
name: 'LoginPage',
9185
components: {
9286
GenericEmail,
87+
GenericPassword,
9388
ErrorAlert,
9489
},
9590
data: () => ({
@@ -103,10 +98,7 @@ export default {
10398
email_errors: [],
10499
105100
password: '',
106-
password_rules: [
107-
v => !!v || 'Enter your password to log in',
108-
],
109-
hide_password: true,
101+
110102
errors: [],
111103
}),
112104
methods: {

0 commit comments

Comments
 (0)