Skip to content

Commit 34ce1be

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

File tree

8 files changed

+154
-94
lines changed

8 files changed

+154
-94
lines changed

www/webapp/src/components/DonateDirectDebitForm.vue

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,10 @@
7575
validate-on-blur
7676
/>
7777

78-
<v-text-field
78+
<generic-email
7979
v-model="email"
80-
label="Email Address (optional)"
81-
:prepend-icon="mdiEmail"
82-
outlined
83-
:rules="email_rules"
84-
:error-messages="email_errors"
85-
validate-on-blur
80+
:errorMessages="email_errors"
81+
:required="false"
8682
/>
8783

8884
<v-btn
@@ -98,10 +94,10 @@
9894

9995
<script>
10096
import axios from 'axios';
101-
import {email_pattern} from '@/validation';
10297
import {digestError} from '@/utils';
10398
import ErrorAlert from '@/components/ErrorAlert.vue';
104-
import {mdiAccount, mdiBank, mdiCash100, mdiEmail, mdiMessageTextOutline} from "@mdi/js";
99+
import {mdiAccount, mdiBank, mdiCash100, mdiMessageTextOutline} from "@mdi/js";
100+
import GenericEmail from "@/components/Field/GenericEmail.vue";
105101
106102
const HTTP = axios.create({
107103
baseURL: '/api/v1/',
@@ -112,6 +108,7 @@
112108
export default {
113109
name: 'DonateDirectDebitForm',
114110
components: {
111+
GenericEmail,
115112
ErrorAlert,
116113
},
117114
data: () => ({
@@ -125,7 +122,6 @@
125122
mdiBank,
126123
mdiCash100,
127124
mdiMessageTextOutline,
128-
mdiEmail,
129125
130126
/* from env */
131127
creditorid: import.meta.env.VITE_APP_DESECSTACK_API_SEPA_CREDITOR_ID,
@@ -154,7 +150,6 @@
154150
155151
/* email field */
156152
email: '',
157-
email_rules: [v => v === '' || !!email_pattern.test(v || '') || 'This is not an email address.'],
158153
email_errors: [],
159154
160155
/* donation interval (every N months) */
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<template>
2+
<v-text-field
3+
v-bind="computedProps"
4+
v-on="$listeners"
5+
/>
6+
</template>
7+
8+
<script>
9+
import {email_pattern} from '@/validation';
10+
import {mdiEmail, mdiEmailLock} from '@mdi/js';
11+
import {VTextField} from 'vuetify/lib/components';
12+
13+
export default {
14+
name: 'GenericEmail',
15+
extends: VTextField,
16+
props: {
17+
value: {
18+
type: String,
19+
required: false,
20+
},
21+
errorMessages: {
22+
type: [String, Array],
23+
default: () => [],
24+
},
25+
label: {
26+
type: String,
27+
required: false,
28+
},
29+
placeholder: {
30+
type: String,
31+
required: false,
32+
},
33+
required: {
34+
type: Boolean,
35+
default: true,
36+
},
37+
standalone: {
38+
type: Boolean,
39+
default: false,
40+
},
41+
readonly: {
42+
type: Boolean,
43+
required: false,
44+
},
45+
autofocus: {
46+
type: Boolean,
47+
required: false,
48+
},
49+
new: {
50+
type: Boolean,
51+
required: false,
52+
},
53+
},
54+
computed: {
55+
computedProps() {
56+
let label = 'Email Address';
57+
if(!this.required) {
58+
label += ' (optional)';
59+
}
60+
if(this.new) {
61+
label = 'New ' + label;
62+
}
63+
if(this.standalone) {
64+
label = '';
65+
}
66+
if(this.label) { // Override if custom is set.
67+
label = this.label;
68+
}
69+
const icon = this.readonly ? mdiEmailLock : mdiEmail;
70+
const ruleDefs = {
71+
required: v => !!v || 'Email is required.',
72+
valid: v => (v !== undefined && !!email_pattern.test(v)) || 'We need an valid email address for account recovery and technical support.',
73+
};
74+
let rules = []
75+
if(this.required) {
76+
rules.push(ruleDefs.required);
77+
}
78+
if(this.new) {
79+
rules.push(ruleDefs.valid);
80+
}
81+
return {
82+
type: 'email',
83+
value: this.value,
84+
'error-messages': this.errorMessages,
85+
label: label,
86+
required: this.required,
87+
disabled: this.readonly,
88+
autofocus: this.autofocus,
89+
placeholder: this.placeholder ?? 'Email Address',
90+
prependIcon: this.standalone ? '' : icon,
91+
prependInnerIcon: this.standalone ? icon : '',
92+
flat: this.standalone,
93+
solo: this.standalone,
94+
outlined: true,
95+
rules: rules,
96+
validateOnInput: true,
97+
}
98+
}
99+
},
100+
};
101+
</script>

www/webapp/src/views/ChangeEmail.vue

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,10 @@
3535
</p>
3636
</v-alert>
3737

38-
<v-text-field
39-
v-model="email"
40-
label="Current Email"
41-
prepend-icon="mdi-blank"
42-
outlined
43-
required
44-
:disabled="true"
45-
validate-on-blur
38+
<generic-email
39+
v-model="email"
40+
label="Current Email Address"
41+
:readonly="true"
4642
/>
4743
<v-text-field
4844
v-model="password"
@@ -59,16 +55,9 @@
5955
ref="password"
6056
tabindex="1"
6157
></v-text-field>
62-
<v-text-field
58+
<generic-email
6359
v-model="new_email"
64-
label="New Email"
65-
prepend-icon="mdi-email"
66-
outlined
67-
required
68-
:rules="[rules.required, rules.email]"
69-
:error-messages="email_errors"
70-
@change="email_errors=[]"
71-
validate-on-blur
60+
:new="true"
7261
tabindex="2"
7362
/>
7463
</v-card-text>
@@ -91,13 +80,13 @@
9180

9281
<script>
9382
import { HTTP, withWorking ,digestError} from '@/utils';
94-
import {email_pattern} from '@/validation';
95-
9683
import ErrorAlert from "@/components/ErrorAlert.vue";
84+
import GenericEmail from "@/components/Field/GenericEmail.vue";
9785
9886
export default {
9987
name: 'ChangeEmail',
10088
components: {
89+
GenericEmail,
10190
ErrorAlert,
10291
},
10392
data: () => ({
@@ -108,7 +97,6 @@
10897
email: '',
10998
rules: {
11099
required: v => !!v || 'Required.',
111-
email: v => !!email_pattern.test(v) || 'Not a valid email address.'
112100
},
113101
show: false,
114102

www/webapp/src/views/DeleteAccount.vue

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,10 @@
3333
</p>
3434
</v-alert>
3535

36-
<v-text-field
36+
<generic-email
3737
v-model="email"
38-
label="Current Email"
39-
prepend-icon="mdi-blank"
40-
outlined
41-
required
42-
:disabled="true"
43-
validate-on-blur
38+
label="Current Email Address"
39+
:readonly="true"
4440
/>
4541
<v-text-field
4642
v-model="password"
@@ -78,10 +74,11 @@
7874
<script>
7975
import { HTTP, withWorking, digestError } from '@/utils';
8076
import ErrorAlert from "@/components/ErrorAlert.vue";
77+
import GenericEmail from "@/components/Field/GenericEmail.vue";
8178
8279
export default {
8380
name: 'DeleteAccount',
84-
components: {ErrorAlert},
81+
components: {GenericEmail, ErrorAlert},
8582
data: () => ({
8683
valid: false,
8784
working: false,

www/webapp/src/views/HomePage.vue

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,11 @@
3131
<v-radio class="pb-2" label="dynDNS account" value="dynDNS"></v-radio>
3232
</v-radio-group>
3333
</div>
34-
<v-text-field
35-
outlined
36-
solo
37-
flat
38-
v-model="email"
39-
:prepend-inner-icon="mdiEmail"
40-
type="email"
41-
placeholder="Account Email Address"
42-
:rules="email_rules"
43-
validate-on-blur
44-
></v-text-field>
34+
<generic-email
35+
v-model="email"
36+
:standalone="true"
37+
:new="true"
38+
/>
4539
<v-btn
4640
color="primary"
4741
type="submit"
@@ -224,10 +218,12 @@ import {
224218
mdiRobot, mdiRunFast,
225219
mdiTwoFactorAuthentication
226220
} from "@mdi/js";
221+
import GenericEmail from "@/components/Field/GenericEmail.vue";
227222
228223
export default {
229224
name: 'HomePage',
230225
components: {
226+
GenericEmail
231227
},
232228
methods: {
233229
async signup() {

www/webapp/src/views/LoginPage.vue

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,10 @@
2727
</v-toolbar>
2828
<v-card-text>
2929
<error-alert :errors="errors"></error-alert>
30-
<v-text-field
31-
v-model="email"
32-
label="Email"
33-
outlined
34-
required
35-
:rules="email_rules"
36-
:error-messages="email_errors"
37-
tabindex="1"
38-
@change="email_errors=[]"
30+
<generic-email
31+
v-model="email"
32+
:autofocus="true"
33+
tabindex="1"
3934
/>
4035
<v-text-field
4136
v-model="password"
@@ -89,22 +84,25 @@
8984
import { HTTP, digestError } from '@/utils';
9085
import ErrorAlert from "@/components/ErrorAlert.vue";
9186
import {useUserStore} from "@/store/user";
87+
import GenericEmail from "@/components/Field/GenericEmail.vue";
9288
9389
export default {
9490
name: 'LoginPage',
9591
components: {
92+
GenericEmail,
9693
ErrorAlert,
9794
},
9895
data: () => ({
9996
user: useUserStore(),
10097
valid: false,
10198
working: false,
102-
email: '',
103-
password: '',
10499
terms: false,
105100
useSessionStorage: false,
106-
email_rules: [v => !!v || 'Please enter the email address associated with your account'],
101+
102+
email: '',
107103
email_errors: [],
104+
105+
password: '',
108106
password_rules: [
109107
v => !!v || 'Enter your password to log in',
110108
],

0 commit comments

Comments
 (0)