1
1
<template >
2
- <div
3
- v-if =" auth?.type=='credentials'"
4
- class =" account-login" >
2
+ <div v-if =" auth?.type == 'credentials'" class =" account-login" >
5
3
<slot name =" head" >
6
4
<div class =" account-login__heading" >
7
5
<h2 class =" heading__title" >
8
- {{ $ t('account.login.welcome_back') }}
6
+ {{ t('account.login.welcome_back') }}
9
7
</h2 >
10
8
<p class =" heading__description" >
11
- {{ $ t('account.login.description') }}
9
+ {{ t('account.login.description') }}
12
10
</p >
13
11
</div >
14
12
</slot >
15
13
<form @submit.prevent =" submit" class =" account-login__form" >
16
14
<label class =" form__control control-login" >
17
15
<div class =" label" >
18
16
<span class =" label-text" >
19
- {{ $ t('account.address.email') }}
17
+ {{ t('account.address.email') }}
20
18
</span >
21
19
</div >
22
- <input type =" email" v-model =" login" class =" control__input" @keyup =" checkValidity('login', $event)" :placeholder =" $t('account.address.email')" />
23
- <div class =" label" >
24
- <span v-if =" error.login" class =" label-text-alt text-error" >{{ $t('error.login.email') }}</span >
25
- </div >
20
+ <input
21
+ type =" email"
22
+ v-model =" login"
23
+ class =" control__input"
24
+ required
25
+ :placeholder =" t('account.address.email')"
26
+ />
26
27
</label >
27
- <label class =" form__control control-password" >
28
- <div class =" label" >
29
- <span class =" label-text" >
30
- {{ $t('account.login.password') }}
31
- </span >
32
- </div >
33
- <label class =" control__input" >
34
- <input
35
- v-model =" password"
36
- :type =" passwordView ? 'text' : 'password'"
37
- :disabled =" loading"
38
- required
39
- class =" grow"
40
- minlength =" 6"
41
- :placeholder =" passwordView ? '' : '*************'"
42
- @keyup =" checkValidity('password', $event)"
43
- />
44
- <button type =" button" @click =" passwordView = !passwordView" class =" cursor-pointer text-lg" >
45
- <icon
46
- class =" view-icon"
47
- :name =" passwordView ? 'view': 'hide'"
48
- />
49
- </button >
50
- </label >
51
- <div class =" label" >
52
- <span v-if =" error.password" class =" label-text-alt text-error" >{{ $t('error.login.password') }}</span >
53
- </div >
54
- <div class =" label" >
55
- <NuxtLink
28
+ <input-password
29
+ v-model =" password"
30
+ :required =" true"
31
+ placeholder =" ***********"
32
+ :disabled =" loading"
33
+ pattern =" .{6,}"
34
+ >
35
+ <template #label >
36
+ {{ t('account.login.password') }}
37
+ </template >
38
+ <template #error ><span ></span ></template >
39
+ <template #label-bottom >
40
+ <nuxt-link
56
41
class =" label-text-alt underline"
57
42
:to =" {
58
43
path: localePath('/account/password-reset'),
59
44
query: { login }
60
45
}"
61
46
>
62
- {{ $ t('account.login.forgot_password') }}
63
- </NuxtLink >
64
- </div >
65
- </label >
47
+ {{ t('account.login.forgot_password') }}
48
+ </nuxt-link >
49
+ </template >
50
+ </input-password >
66
51
<div class =" form__submit" >
67
- <div v-if =" error.auth" class =" submit__error" >
68
- <icon class =" text-xl" name =" error" />
69
- {{ error.auth }}
70
- </div >
71
- <button type =" submit" class =" submit__btn " :disabled =" loading" >
52
+ <button type =" submit" class =" submit__btn" :disabled =" loading" >
72
53
<span v-if =" loading" class =" loading loading-spinner" ></span >
73
- {{ $ t('account.login.sign_in') }}
54
+ {{ t('account.login.sign_in') }}
74
55
</button >
56
+ <div v-if =" error" class =" submit__error" >
57
+ <icon class =" w-12" name =" error" />
58
+ {{ error }}
59
+ </div >
75
60
</div >
76
61
</form >
77
62
<div class =" account-login__footer" >
78
63
<slot name =" footer" >
79
64
<p class =" footer-content" >
80
65
<span class =" footer-content__text" >
81
- {{ $ t('account.login.not_yet_account') }}
66
+ {{ t('account.login.not_yet_account') }}
82
67
</span >
83
- <nuxt-link
84
- class =" footer-content__link"
85
- :to =" localePath('/account/register')"
86
- >
87
- {{ $t('account.login.create_account') }}
68
+ <nuxt-link class =" footer-content__link" :to =" localePath('/account/register')" >
69
+ {{ t('account.login.create_account') }}
88
70
</nuxt-link >
89
71
</p >
90
72
</slot >
96
78
</div >
97
79
</div >
98
80
</template >
99
- <script lang="ts">
81
+ <script lang="ts" setup >
100
82
import type { AuthCredentialService } from ' #services'
101
- import LogoVue from ' ../global/Logo.vue '
83
+ import { erpApiGetErrorMessagesAsStr } from ' ~/utils/ErpApiHelper '
102
84
103
- export default defineNuxtComponent ({
104
- name: ' AccountLogin' ,
105
- components: {
106
- logo: LogoVue
107
- },
108
- data() {
109
- return {
110
- login: ' ' as string | null ,
111
- password: ' ' as string | null ,
112
- passwordView: false as boolean ,
113
- loading: false as boolean ,
114
- error: {
115
- auth: null as string | null ,
116
- login: null as string | null ,
117
- password: null as string | null ,
118
- message: null as string | null
119
- }
120
- }
121
- },
122
- setup() {
123
- const localePath = useLocalePath ()
124
- const auth = useShopinvaderService (' auth' ) as AuthCredentialService | null
85
+ const localePath = useLocalePath ()
86
+ const auth = useShopinvaderService (' auth' ) as AuthCredentialService | null
125
87
126
- onMounted (async () => {
127
- if (! auth ?.getUser ()?.value && auth ?.type == ' oidc' ) {
128
- const url = useRequestURL ()
129
- await auth ?.loginRedirect (url ?.href )
130
- }
131
- })
132
- return {
133
- localePath ,
134
- auth
88
+ const emit = defineEmits ([' success' ])
89
+ const { t } = useI18n ()
90
+ const login = ref <string >(' ' )
91
+ const password = ref <string >(' ' )
92
+ const loading = ref <boolean >(false )
93
+ const error = ref <string | null >(null )
94
+
95
+ onMounted (async () => {
96
+ if (! auth ?.getUser ()?.value && auth ?.type == ' oidc' ) {
97
+ const url = useRequestURL ()
98
+ await auth ?.loginRedirect (url ?.href )
99
+ }
100
+ })
101
+
102
+ /*
103
+ * Submit the login form
104
+ */
105
+ const submit = async (_e : Event ) => {
106
+ loading .value = true
107
+ error .value = null
108
+
109
+ try {
110
+ login .value = login .value ?.trim ()
111
+ if (! login .value || ! password .value ) {
112
+ throw new Error (t (' error.login.unable_to_login' ))
135
113
}
136
- },
137
- methods: {
138
- checkValidity(input : " login" | " password" , e : Event ) {
139
- const target = e .target as HTMLInputElement
140
- const validity = target ?.checkValidity ()
141
- this .error = {
142
- ... this .error ,
143
- [input ] : ! validity || target ?.value === ' '
144
- }
145
- },
146
- async submit(_e : Event ) {
147
- const auth = this .auth
148
- this .loading = true
149
- if (this ?.login && this ?.password ) {
150
- try {
151
- await auth ?.login (this .login , this .password )
152
- this .$emit (' success' )
153
- } catch (e ) {
154
- this .error .auth = this .$t (' error.login.unable_to_login' )
155
- } finally {
156
- this .loading = false
157
- }
158
- }
114
+ const user = await auth ?.login (login .value , password .value )
115
+ if (! user ) {
116
+ // Null user means login failed
117
+ error .value = t (' error.login.unable_to_login' )
118
+ } else {
119
+ emit (' success' )
159
120
}
121
+ } catch (e ) {
122
+ // Display the error message
123
+ error .value = erpApiGetErrorMessagesAsStr (e ) || t (' error.generic' )
124
+ } finally {
125
+ loading .value = false
160
126
}
161
- })
127
+ }
162
128
</script >
163
129
<style lang="scss">
164
130
.account-login {
165
- @apply flex flex-col max-w-sm ;
131
+ @apply flex max-w-sm flex-col ;
166
132
& __form {
167
-
168
133
@apply card card-body card-bordered rounded-b-none bg-white ;
169
134
.form {
170
135
& __control {
171
-
172
136
@apply form-control w-full max-w-xs ;
173
137
.control {
174
138
& __input {
175
139
@apply input input-bordered w-full max-w-xs ;
176
140
}
177
-
178
141
}
179
142
& .control-password {
180
- .control__input {
143
+ .control__input {
181
144
@apply flex items-center gap- 2;
182
145
}
183
146
}
184
147
}
185
148
.form__control {
186
149
& .control-password {
187
-
188
150
.control {
189
151
& __input {
190
- @apply items-center gap- 2;
152
+ @apply items-center gap- 2;
191
153
}
192
154
}
193
155
}
@@ -196,7 +158,7 @@ export default defineNuxtComponent({
196
158
@apply flex flex-col justify-center ;
197
159
.submit {
198
160
& __error {
199
- @apply flex items-center justify-center text-error py-4 gap- 1 ;
161
+ @apply flex items-start justify-center gap-1 py-4 text-error ;
200
162
}
201
163
& __btn {
202
164
@apply btn btn-primary btn-block ;
@@ -217,14 +179,14 @@ export default defineNuxtComponent({
217
179
}
218
180
}
219
181
& __footer {
220
- @apply card card-body bg-primary-800 text-primary-content rounded-t-none ;
182
+ @apply card card-body rounded-t-none bg-primary-800 text-primary-content ;
221
183
.footer-content {
222
- @apply flex flex-col justify -center items -center gap- 2;
184
+ @apply flex flex-col items -center justify -center gap- 2;
223
185
& __text {
224
186
@apply text-lg ;
225
187
}
226
188
& __link {
227
- @apply btn btn-sm bg-white ;
189
+ @apply btn btn-sm bg-white ;
228
190
}
229
191
}
230
192
}
0 commit comments